【发布时间】:2018-09-20 23:24:57
【问题描述】:
在使用锁时是否需要volatile 修饰符以保证内存可见性?
试图完全理解并发性、内存可见性和执行控制我遇到了几个消息来源,说在synchronized 块中更新的变量不需要字段是volatile(大多数情况下没有给出来源,实际上有一页说同步方法和波动率字段需要结合使用)。
接近jls chapter 17.4.5时发现:
两个动作可以通过happens-before关系排序。如果一个动作 发生在另一个之前,那么第一个对第二个可见并在第二个之前排序。
这部分是否说后续同步方法调用保护相同的变量变量将确保它对第二个线程可见?如果是这种情况,由于我们也可以保证订单,因此锁也同样适用吗?
另一方面,当我们突然拥有允许 2 个线程访问该字段的写锁时会发生什么。即使变量被解锁,整个构造是否崩溃并且线程永远无法保证更新其缓存?
简短的代码
int field; //volatile not needed because we have a definite happens-before relationship
Lock lock;
void update(){
//No matter how many threads access this method they will always have
//the most up to date field value to work with.
lock.lock()
field *= 2;
lock.unlock();
}
【问题讨论】:
-
variables updated in synchronized blocks do not require the field to be volatile这是正确的。 -
对紧接在此之前的问题:
If this is the case does the same hold true for locks since we can also guarantee an order?是的,如果文档说锁具有内存可见性副作用,则也是。 大多数锁来自 @ 987654328@ 在他们的 API 文档中有这样的注释。 -
您的“短代码”仍然不是线程安全的。因为您使用锁来同步更新,但您未能保护实例变量
field免受其他线程读取它并执行复合操作。使您的“短代码”线程安全。您需要 volatile 实例字段或封装它们并同步访问器方法。 -
一个读写锁只允许多个读者。这些读取器与写入器的最后一次更新仍然具有发生前的排序关系。
标签: java multithreading concurrency java-memory-model