Java 同步实例而不是易失性原语
我有一个目标:Java 同步实例而不是易失性原语,java,multithreading,memory-management,thread-safety,Java,Multithreading,Memory Management,Thread Safety,我有一个目标: class Data{ int a; int b; AtomicIntegerArray c = new AtomicIntegerArray(10000); } 在以下场景中,线程A和线程B使用此对象: A创建一个数据(现在称为“数据”) 将数据发送到队列 B从队列中读取,获取数据 B将数据的字段和信号更新到A,表明数据已被处理 B睡觉 A开始处理数据的字段 现在,到目前为止,我为确保内存可见性所做的工作是: class Data{ volat
class Data{
int a;
int b;
AtomicIntegerArray c = new AtomicIntegerArray(10000);
}
在以下场景中,线程A和线程B使用此对象:
A创建一个数据(现在称为“数据”)
将数据发送到队列
B从队列中读取,获取数据
B将数据的字段和信号更新到A,表明数据已被处理
B睡觉
A开始处理数据的字段
现在,到目前为止,我为确保内存可见性所做的工作是:
class Data{
volatile int a;
volatile int b;
volatile AtomicIntegerArray c = new AtomicIntegerArray(10000);
}
这是可行的,但让我担心。当线程A返回数据时,它只需要在开始时同步它的内存一次,而不是每次它接触字段时。我想我可以通过简单的尝试来实现这一点:
synchronized(data){}
一旦知道数据已经更新,就使用第一个数据实现。这样我只做一次代价高昂的内存同步
我说得对吗?在将数据“移交”给线程A之前,我是否还需要确保线程B同步数据
请记住,我只对内存同步/可见性感兴趣,没有锁机制,线程之间的信令也不重要。我已经办妥了
信号:
class A implements callback{
private volatile boolean dataProcessed;
private final Data data = new Data();
@Override
public void dataHasBeenProcessed(){
dataProcessed = true;
}
void someMethod(){
dataProcessed = false;
threadB.processData(data, this);
while(!dataProcessed)
...sleep;
data.workOnFields();
}
因此,A将数据发送给B,然后在处理数据时轮询B在回调方法中设置的易失性布尔值;DR您根本不需要
volatile
或synchronized
线程A和B从不同时接触对象,因此只要它们之间的切换建立了“发生在边界之前”的边界,它们就会始终看到最新的数据
例如,如果队列为a,则您可以获得以下保证:
内存一致性影响:与其他并发集合一样,在将对象放入阻塞队列
之前,线程中的操作发生在另一个线程中从阻塞队列
访问或移除该元素之后的操作之前
因此,只要队列是阻塞队列
,而不是泛型队列,那么从线程a到线程B的转移是安全的
如果从线程B返回到线程A的信号正在使用例如A执行,则您将获得以下保证:
内存一致性影响:在计数达到零之前,调用countDown()
之前线程中的操作发生在另一个线程中相应的wait()
成功返回后的操作之前
因此,从线程B切换回线程A也是安全的
摘要:
- 线程A在发送对象之前所做的一切都发生在线程B接收对象之前
- 线程B在发送信号之前所做的一切都发生在线程A接收信号之前
volatile
或synchronized
我说得对吗?在将数据“移交”给线程A之前,我是否还需要确保线程B同步数据
由于您使用volatile
变量建立了之前发生的事件,您是正确的。如果线程B向volatile变量dataProcessed
写入数据,那么它将使读取相同volatile变量的线程A可以使用其所有内存更改(到Data
)
既然您询问内存可见性,可以这样想:当线程B写入易失性变量时,它保证将它更改的所有变量(数据
)刷新到主内存中。(线程B在CPU内核上运行)。线程A现在可以看到所有内容。这就是“先发生后发生”关系的本质
虽然它可以工作,但这不是一个好的设计。您有一个由多个线程共享的对象(
数据
)。此对象应该是线程安全的。假设将来有人添加了一个线程C,并且忘记了强制执行“发生在发生之前”关系。这将引入难以发现的同步错误,这些错误通常需要很长时间才能识别,因为它们间歇性或很少发生。这是个好消息。不幸的是,据我所知,我没有确定任何发生在边界之前的事件。这两个线程通过分配易失性指针进行通信。例如,当B处理完数据后,它将一个空指针分配给数据的指针,a在B的执行过程中依次轮询该指针。我的队列是另一回事,但它不是阻塞队列。所以,让我们玩一玩我没有建立任何东西的想法。那么你有什么要说的?>B更新数据的字段,并向A发送数据已被处理的信号。B如何向A发送信号?你能粘贴那个代码吗?当然,我已经更新了作为答案的帖子。太大,无法放入评论:)谢谢!我知道设计问题,但我的目标是与产生的0垃圾进行良好的通信。我认为volatile只确保volatile标记的变量在写入时被刷新,也就是说不是过时的,也不是所有线程缓存的变量。但情况似乎是这样。