为了账号安全,请及时绑定邮箱和手机立即绑定

同步、易失性和(标记)锁的 Java 内存模型交互

同步、易失性和(标记)锁的 Java 内存模型交互

MMTTMM 2021-09-29 13:17:55
volatile使用锁时是否需要修饰符来保证内存可见性?试图完全理解并发性、内存可见性和执行控制我遇到了几个消息来源说在synchronized块中更新的变量不需要该字段volatile(大多数没有提供来源,实际上有一页说需要结合使用同步方法和波动性字段)。当接近jls 第 17.4.5 章时,我发现:两个动作可以通过happens-before 关系排序。如果一个动作发生在另一个之前,那么第一个动作对第二个动作可见并在第二个动作之前排序。这部分是说后续同步方法调用保护相同的变量变量将确保它对第二个线程可见吗?如果是这种情况,锁也一样吗,因为我们也可以保证订单?另一方面,当我们突然拥有允许 2 个线程访问该字段的写锁时会发生什么。即使在变量被解锁的情况下,整个构造是否会崩溃并且线程也永远不会保证更新它们的缓存?简而言之int field; //volatile not needed because we have a definite happens-before relationshipLock 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();}
查看完整描述

3 回答

?
胡子哥哥

TA贡献1825条经验 获得超6个赞

使用锁时是否需要 volatile 修饰符以保证内存可见性?

volatile变量只保证内存可见性,但不保证原子性。这是Java 中块volatilesynchronized块的主要区别之一。因此,当您使用synchronized块时,变量不必是volatile. 但是如果您的变量是volatile并且对该变量执行任何复合操作,那么您需要volatile使用锁来保护对变量的更新。

这部分是说后续同步方法调用保护同一变量将确保它对第二个线程可见吗?如果是这种情况,锁也一样吗,因为我们也可以保证订单?

是的。因为锁会给你带来可见性和原子性。

另一方面,当我们突然拥有允许 2 个线程访问该字段的写锁时会发生什么。即使在变量被解锁的情况下,整个构造是否会崩溃并且线程也永远不会保证更新它们的缓存?

如果您在同一锁上保护对变量的更新,则在任何给定时间只有一个线程可以处理该变量。所以它保证了一致性。但是如果每次都使用不同的锁来保护那个变量,那么多个线程将修改变量状态,并可能使变量状态不一致。因此,在这种情况下,可见性和原子性都得到了保证,但仍然会导致不一致。


查看完整回答
反对 回复 2021-09-29
?
互换的青春

TA贡献1797条经验 获得超6个赞

...实际上有一页说同步方法和波动性字段需要结合使用。

您可以提炼出您需要了解的有关内存可见性和synchronized块的所有信息,并将其归结为一个简单的规则。也就是说,线程 A 在退出synchronized (o) {...}块之前对共享变量和对象所做的任何事情都保证在线程 B 进入同一对象synchronized (o) {...}块时对线程 B 可见。 o

而且,正如@markspace 已经说过的,任何实现java.util.concurrent.locks.Lock都需要以相同的方式工作。


查看完整回答
反对 回复 2021-09-29
  • 3 回答
  • 0 关注
  • 135 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信