JMM是否保证synchronized写入到在synchronized块之后在另一个线程中读取的变量的可见性?我的意思是:
public class SynchronizedWriteRead {
private int a;
private int b;
public void writer() {
synchronized (this) {
a = 5;
b = 7;
}
}
public void reader() {
synchronized (this) {
int r1 = a; /* 5 */
}
int r2 = b; /* ? */
}
}JMM保证监视器上的解锁发生--在该监视器上的每个后续锁之前。但我不确定它是否只与synchronized块体有关。
最近我遇到了来自Aleksey Shipil v- Java中的安全发布和安全初始化的这篇文章。上面写着:
请注意,在不安全的DCL存储中执行是如何没有帮助的,与外行人所认为的相反,它以某种方式神奇地“刷新缓存”或诸如此类。在读取受保护状态时,如果没有配对锁,则无法保证在受锁保护的写入之前看到写入。
这就是我问自己这个问题的原因。我在JLS上找不到答案。
换个说法吧。有时,您正在依赖volatile --在像这样的保证之前:
public class VolatileHappensBefore {
private int a; /* specifically non-volatile */
private volatile int b;
public void writer() {
a = 5;
b = 7;
}
public void reader() {
int r1 = b; /* 7 */
int r2 = a; /* 5 */
}
}您肯定会看到这两种写操作,因为在同一线程中的顺序操作在发生之前和发生之前都有支持,然后才是传递性的。
我是否可以使用发生的synchronized -在以同样的方式保证之前?甚至可能是这样(我已经将sync变量设置为禁止编译器/JVM删除否则为空的synchronized块):
public void writer() {
a = 5;
b = 7;
synchronized (this) {
sync = 1;
}
}
public void reader() {
synchronized (this) {
int r = sync;
}
int r1 = a; /* ? */
int r2 = b; /* ? */
}发布于 2022-08-06 01:52:45
这里需要注意的是,在此之前发生的是传递的关系。因此,如果A发生--在B和B发生之前--在C之前,我们可以安全地得出结论,A发生在C之前。
现在,让我们看一下所讨论的代码(为了清楚起见,我添加了注释):
public void writer() {
a = 5; //1
b = 7; //2
synchronized (this) {
sync = 1;
} //3
}
public void reader() {
synchronized (this) { //4
int r = sync;
}
int r1 = a; //5
int r2 = b; //6
}我们知道1发生在2之前,2在3之前,因为它们是由同一个线程执行的:
如果x和y是同一个线程的动作,x以程序顺序出现在y之前,则hb(x,y)。
我们也知道3发生在4之前
监视器m上的解锁操作同步-与m上的所有后续锁操作同步(其中“后继”根据同步顺序定义)。如果一个动作x与以下动作y同步,那么我们也有hb(x,y)。
最后,我们知道4发生在5之前,5在6之前,因为它们是在同一个线程中执行的。
如果x和y是同一个线程的动作,x以程序顺序出现在y之前,则hb(x,y)。
因此,我们最终会有一系列的事情发生--在关系从1到6之前。因此,1发生在6之前。
发布于 2022-08-16 07:42:20
你现在已经得到了答案,公平地说,这里的每个人都是正确的,我只想补充一条重要的规则。它被称为“在一致性之前发生”,它是这样的:
因此,虽然公认的答案确实是正确的,但应该提到,为了在(3)和(4)之间创建边界之前,(4)必须遵守(3)所做的写。
在你的例子中:
public void reader() {
synchronized (this) {
int r = sync;
}
int r1 = a; /* ? */
int r2 = b; /* ? */
}这意味着int r = sync;是不正确的,您需要断言您实际上看到了sync是1 (您已经观察到了写入)。例如,这将创建所需的边缘:
if (sync == 1) {
// guaranteed that r1=5 and r2=7
int r1 = a;
int r2 = b;
}发布于 2022-08-05 23:19:42
JMM是否保证
synchronized写入到在synchronized块之后在另一个线程中读取的变量的可见性?在保证同样的方式之前,我可以使用同步发生吗?
是的,是的。
synchronized和volatile提供了相同的可见性保证。
实际上,volatile变量的行为就好像每个变量的读和写都发生在它自己的小synchronized块中。
用JLS术语来说:
volatile和synchronized是建立发生前关系的一些方法:引用Java中的安全发布和安全初始化的话描述了以下情况:
synchronized块中初始化。synchronized块的情况下读取synchronized的。在这种情况下,读取器线程可能会看到初始化过程中的对象。
https://stackoverflow.com/questions/73251592
复制相似问题