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标记的变量在写入时被刷新,也就是说不是过时的,也不是所有线程缓存的变量。但情况似乎是这样。