【发布时间】:2019-10-18 16:54:34
【问题描述】:
Java Concurrency in Practice 陈述如下:
当线程 A 执行一个同步块,随后线程 B 进入由同一个锁保护的同步块,值 在释放锁之前对 A 可见的变量是 保证在获得锁时对 B 可见。换一种说法, A 在或在同步块之前所做的一切对 B 可见,当 它执行由同一个锁保护的同步块。 没有同步,就没有这样的保证。
同样的逻辑也适用于 volatile 变量:
volatile 变量的可见性影响超出了值 volatile 变量本身。当线程 A 写入 volatile 变量,随后线程 B 读取相同的变量, 在写入之前对 A 可见的所有变量的值 volatile 变量在读取 volatile 后对 B 可见 变量。
从描述中可以非常清楚地看到,当您需要访问某些共享状态时,您可以使用这种可见性效果来实际替换(或限制使用)传统锁。在图中的示例中,您可以看到线程 B 可以安全地读取变量 y,即使它在同步块之外的线程 A 中被更改。
那么,当您在锁定线程之前更改某些共享状态,然后获取锁定,做某事(或者什么都不做,我猜),释放锁定,然后在其他线程你获得相同的锁,释放它,然后安全地从第一个线程中更新的共享变量中读取最新值?
【问题讨论】:
-
同步确保线程 A 将在线程 B 进入之前完成该块。而
volatile只会在线程 A 和 B 不同时读取/写入成员时生效。例如。当线程 A 和 B 同时写入成员m时,您无法保证将写入和读取哪个值。线程 C 收到的值几乎是不确定的(你根本无法确定) -
我不太确定您要回答问题的哪一部分。我的问题主要是关于释放锁时 JVM 提供的可见性保证。在我提到的示例图中,您可以看到
y变量在同步块之外发生了更改,但仍然可以从线程 B 安全地访问,该线程 B 在释放锁后访问该变量。 -
所以你基本上会问这本书是不是在骗你?您有什么理由不信任它而信任我们?
-
我基本上是在问为什么我应该使用同步块(或 java.util.concurrent.locks 包中的一些锁对象)并将任何处理共享状态的代码放入其中,当我可以使用书中描述的技术并尽可能限制锁/同步块的使用(例如,不包括其中的任何内容),因为
reader线程无论如何都可以获得最近的更改? -
@J.Doe 我准确地回答了你最后的评论。当您不使用
synchronization时,您无法确定您的reader线程是否遇到了有效值,也许它在另一个线程正在写入的同时从字段中读取值。
标签: java multithreading concurrency