首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >同步实例而不是易失性原语

同步实例而不是易失性原语
EN

Stack Overflow用户
提问于 2017-08-03 19:16:56
回答 2查看 64关注 0票数 1

我有一个目标:

代码语言:javascript
复制
class Data{
   int a;
   int b;
   AtomicIntegerArray c = new AtomicIntegerArray(10000);   
}

线程A和B在以下场景中使用此对象:

A创建数据(现在称为“数据”)

A将数据发送到队列。

B从队列中读取,获取数据。

B向A更新数据的字段和信号,即数据已被处理。

B睡觉。

A开始处理数据字段。

到目前为止,我为确保内存可见性所做的工作是:

代码语言:javascript
复制
 class Data{
   volatile int a;
   volatile int b;
   volatile AtomicIntegerArray c = new AtomicIntegerArray(10000);   
}

这很管用,但让我很担心。当线程A返回数据时,它只需要在开始时同步它的内存一次,而不是每次它接触到一个字段时。我想我可以通过简单的A来实现这一点:

代码语言:javascript
复制
synchronized(data){}

一旦它知道数据已经被更新,从而使用了数据的第一个实现。这样,我只进行一次代价高昂的内存同步。

我说的对吗?我还需要确保线程B在将数据“交给”线程A之前同步吗?

请记住,我只对内存同步/可见性感兴趣,不关心锁机制和线程之间的信令。我已经把它盖好了。

信号:

代码语言:javascript
复制
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在回调方法中设置该布尔值。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-08-05 16:51:52

我说的对吗?我还需要确保线程B在将数据“交给”线程A之前同步吗?

由于您已经使用happens-before变量建立了volatile,所以是正确的。如果线程B写入易失性变量dataProcessed,则将其所有内存更改(到Data)提供给读取相同易失性变量的线程A。

由于您询问了内存可见性,请这样想:当线程B写入易失性变量时,可以保证将其更改的所有变量(Data)都刷新为主内存。(线程B运行在CPU核心上)。线程A现在可以看到它的全部。这是发生前关系的本质。

虽然它工作,但这不是一个好的设计。您有一个由多个线程共享的对象(Data)。这个对象应该是线程安全的.假设将来有人添加了一个线程C,并且忘记了强制执行发生之前的关系。这将导致很难找到通常需要很长时间才能识别的同步错误,因为它们是间歇性的或很少发生的。

票数 0
EN

Stack Overflow用户

发布于 2017-08-03 19:26:56

TL;博士,你根本不需要volatilesynchronized

线程A和B从不同时接触对象,因此只要它们之间的切换建立了边界之前发生的事件,它们就会始终看到最新的数据。

例如,如果队列是BlockingQueue,则得到以下保证:

内存一致性效应:与其他并发集合一样,在将对象放入BlockingQueue之前,线程中的操作会在访问或从另一个线程中的BlockingQueue中删除该元素之后发生。

因此,只要队列是一个BlockingQueue,而不是一般的Queue,线程A到线程B之间的切换就是安全的。

如果从线程B返回到线程A的信号正在使用例如CountDownLatch,则可以得到以下保证:

内存一致性效应:在计数达到零之前,在调用countDown()之前发生线程中的操作--在另一个线程成功返回相应的await()之后执行操作。

所以从线程B到线程A的切换也是安全的.

摘要:

  • 线程A在发送对象之前所做的一切都发生在线程B接收对象之前。
  • 线程B在发送信号之前所做的一切都发生在线程A接收信号之前。

结论:

不需要volatilesynchronized

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45492808

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档