有些人说如果多个线程正在读/写,那么你需要使用synchronized,如果一个线程正在读/写,而另一个线程只读,那么你必须使用volatile。我不能解决这种情况。
基本上,在写操作完成后,所有读者(特别是其他线程)都可以看到volatile字段的值。
然后如果我将变量定义为volatile,则首先threadA将读取其值,threadA将更新其值并将其写入内存。此变量将对threadB可见。那为什么我需要同步块?
答案 0 :(得分:2)
有些人说如果多个线程正在读/写,那么你需要使用synchronized,如果一个线程正在读/写,而另一个线程只读,那么你必须使用volatile。我没有区分这种情况。
这确实没有硬性规定。选择是否使用synchronized
或volatile
更多地与 对象的更新有关,而不是有多少读者或作者。
例如,您可以使用AtomicLong
创建包含volatile long
的多个读者和作者。
private AtomicLong counter = new AtomicLong();
...
// many threads can get/set this counter without synchronized
counter.incrementAndGet();
在某些情况下,即使只有一个读写器,您也需要synchronized
块。
synchronized (status) {
status.setNumTransactions(dao.getNumTransactions());
// we don't want the reader thread to see `status` partially updated here
status.setTotalMoney(dao.getTotalMoney());
}
在上面的示例中,由于我们正在进行多次调用以更新status
对象,因此我们可能需要确保其他线程在更新num-transactions时不会看到它而不是总金额。是的,AtomicReference
处理其中一些案件,但不是全部。
要清楚,标记字段volatile
可确保内存同步。当您读取volatile
字段时,您会跨越读取内存屏障,当您编写它时,会跨越写入内存屏障。 synchronized
块在开始时具有读取内存屏障,并且块和末尾的写入屏障具有互斥锁定,以确保只有一个线程可以立即进入块。 / p>
有时你只需要内存屏障来实现线程之间正确的数据共享,有时你需要锁定。
答案 1 :(得分:0)
正如评论所示,您可能会进一步阅读。但是为了给你一个想法,你可以看看这个stackoverflow question并想一想下面的场景:
您有几个需要处于正确状态的变量。但是,尽管你使它们都变得易变,但你需要时间来通过执行某些代码来更新它们。
这个代码几乎可以由不同的线程同时执行。第一个变量可能是“OK”并且以某种方式同步,但是其他一些变量可能依赖于第一个并且还不正确。因此,在这种情况下你需要一个同步块。
添加一个帖子以进一步阅读有关易变look here
的信息答案 2 :(得分:0)
volatile和synchronized之间的主要区别是volatile只保证可见性,而synchronized保证可见性和锁定。
如果有多个读取线程和一个写入线程,则volatile的使用可以确保写入线程对volatile变量的更改立即对其他线程可见。但是你看,在这种情况下,锁定不是问题,因为你只有1个写线程。
对于不稳定因素有一些经验法则:
一般情况下,volatile的使用应仅限于那些相对容易推理其状态的情况,例如状态标志。
在所有其他共享可变状态的情况下,除了声明final和仅在构造函数中修改而没有不安全的发布时,总是使用synchronized来触及共享可变状态。 Volatile是仅在特殊情况下同步的替代品,如我的3点所述。