我有一个目标:
class Data{
int a;
int b;
AtomicIntegerArray c = new AtomicIntegerArray(10000);
}线程A和B在以下场景中使用此对象:
A创建数据(现在称为“数据”)
A将数据发送到队列。
B从队列中读取,获取数据。
B向A更新数据的字段和信号,即数据已被处理。
B睡觉。
A开始处理数据字段。
到目前为止,我为确保内存可见性所做的工作是:
class Data{
volatile int a;
volatile int b;
volatile AtomicIntegerArray c = new AtomicIntegerArray(10000);
}这很管用,但让我很担心。当线程A返回数据时,它只需要在开始时同步它的内存一次,而不是每次它接触到一个字段时。我想我可以通过简单的A来实现这一点:
synchronized(data){}一旦它知道数据已经被更新,从而使用了数据的第一个实现。这样,我只进行一次代价高昂的内存同步。
我说的对吗?我还需要确保线程B在将数据“交给”线程A之前同步吗?
请记住,我只对内存同步/可见性感兴趣,不关心锁机制和线程之间的信令。我已经把它盖好了。
信号:
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在回调方法中设置该布尔值。
发布于 2017-08-05 16:51:52
我说的对吗?我还需要确保线程B在将数据“交给”线程A之前同步吗?
由于您已经使用happens-before变量建立了volatile,所以是正确的。如果线程B写入易失性变量dataProcessed,则将其所有内存更改(到Data)提供给读取相同易失性变量的线程A。
由于您询问了内存可见性,请这样想:当线程B写入易失性变量时,可以保证将其更改的所有变量(Data)都刷新为主内存。(线程B运行在CPU核心上)。线程A现在可以看到它的全部。这是发生前关系的本质。
虽然它工作,但这不是一个好的设计。您有一个由多个线程共享的对象(Data)。这个对象应该是线程安全的.假设将来有人添加了一个线程C,并且忘记了强制执行发生之前的关系。这将导致很难找到通常需要很长时间才能识别的同步错误,因为它们是间歇性的或很少发生的。
发布于 2017-08-03 19:26:56
TL;博士,你根本不需要volatile或synchronized。
线程A和B从不同时接触对象,因此只要它们之间的切换建立了边界之前发生的事件,它们就会始终看到最新的数据。
例如,如果队列是BlockingQueue,则得到以下保证:
内存一致性效应:与其他并发集合一样,在将对象放入
BlockingQueue之前,线程中的操作会在访问或从另一个线程中的BlockingQueue中删除该元素之后发生。
因此,只要队列是一个BlockingQueue,而不是一般的Queue,线程A到线程B之间的切换就是安全的。
如果从线程B返回到线程A的信号正在使用例如CountDownLatch,则可以得到以下保证:
内存一致性效应:在计数达到零之前,在调用
countDown()之前发生线程中的操作--在另一个线程成功返回相应的await()之后执行操作。
所以从线程B到线程A的切换也是安全的.
摘要:
结论:
不需要volatile或synchronized。
https://stackoverflow.com/questions/45492808
复制相似问题