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

标签 java multithreading concurrency java-memory-model

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

在尝试完全理解并发性、内存可见性和执行控制时,我遇到了多个消息来源,称在 synchronized block 中更新的变量不需要该字段是 volatile (大多数情况下)没有给出任何来源,实际上有一页说同步方法和波动性字段需要结合使用)。

当接近jls chapter 17.4.5时我发现:

Two actions can be ordered by a happens-before relationship. If one action happens-before another, then the first is visible to and ordered before the second.

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

另一方面,当我们突然拥有允许 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();
}

最佳答案

摘自Lock的API文档:

https://docs.oracle.com/javase/10/docs/api/java/util/concurrent/locks/Lock.html

All Lock implementations must enforce the same memory synchronization semantics as provided by the built-in monitor lock, as described in Chapter 17 of The Java™ Language Specification:

  • A successful lock operation has the same memory synchronization effects as a successful Lock action.
  • A successful unlock operation has the same memory synchronization effects as a successful Unlock action.

Unsuccessful locking and unlocking operations, and reentrant locking/unlocking operations, do not require any memory synchronization effects.

在我看来,这有点不清楚,但要点是,是的,Lock 需要以与监视器相同的方式工作(synchronized 关键字的作用),并且因此,您的示例始终使 field 的最新更新可见,而无需显式使用 volatile 关键字。

附注获取 Brian Goetz 的Java 并发实践,它更详细地解释了所有这些内容。它基本上是 Java 并发方面的圣经。

关于同步、 volatile 和(标记)锁的 Java 内存模型交互,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52410444/

相关文章:

c++ - OpenCV 在不同线程上运行来自网络摄像头的视频

c++ - 为什么没有像 pthread_mutex_t & std::mutex 那样的 std::等价于 pthread_spinlock_t?

java - 实现多线程访问的java映射,每个键只更新一次

iOS GCD Max 并发操作

java - Json 到 avro 的转换

c# - 在 C# 中的 Parallel.ForEach 中读写字典条目是否安全

java - 滚动后 ListView 项目保持突出显示

Java:使来自多个客户端的并发 MySQL 查询同步

java - 使用 MVC 和 DAO 模式在 JSP 页面中以 HTML 格式显示 JDBC ResultSet

Java - 字符串到 StringReader