Java 锁获取时的内存可见性

Java 锁获取时的内存可见性,java,concurrency,Java,Concurrency,内存可见性是否取决于使用的监视器?在释放锁A后获取锁B,这是否足以使内存可见 例如,以下代码: int state; // shared // thread A synchronized (A) { state += 1; } Thread.sleep(10000000); // thread B Thread.sleep(1000); synchronized(B) { state += 1; } 线程在同一时间启动,线程B睡眠时间可以任意高,只是为了确保在线程A使用状态变量后执行

内存可见性是否取决于使用的监视器?在释放锁
A
后获取锁
B
,这是否足以使内存可见

例如,以下代码:

int state; // shared


// thread A
synchronized (A) {
 state += 1;
}
Thread.sleep(10000000);

// thread B
Thread.sleep(1000);
synchronized(B) {
 state += 1;
}
线程在同一时间启动,线程
B
睡眠时间可以任意高,只是为了确保在线程
A
使用
状态
变量后执行。线程
A
睡眠时间用于确保线程在线程
B
使用
状态
共享变量之前不会完成

更新

如果这是真的,那么我看不出
状态
变量对线程
B

此外,他们说监视器应该是相同的,但这并不是从上述声明中暗示的

This process guarantees that when a variable is written by one thread during a synchronized block protected by a given monitor and read by another thread during a synchronized block protected by the same monitor, the write to the variable will be visible by the reading thread. 

似乎本地内存刷新的过程不像第一条语句中描述的那样简单,可能不会在每次锁释放时都发生?

是的,这取决于具体情况。你可以读一下这个。相关章节为“17.4.4.同步顺序”:

监视器m上的解锁操作与m上的所有后续锁定操作同步(其中“后续”是根据同步顺序定义的)

你看,这里指定了一个具体的监视器对象
m
。如果监视器不同,则您不会得到与关系的同步,因此,您不会得到发生在关系之前(从17.4.5开始):

如果动作x与后续动作y同步,那么我们还有hb(x,y)


因此,您的更新将按顺序执行,可能会丢失更新。

是的,视情况而定。你可以读一下这个。相关章节为“17.4.4.同步顺序”:

监视器m上的解锁操作与m上的所有后续锁定操作同步(其中“后续”是根据同步顺序定义的)

你看,这里指定了一个具体的监视器对象
m
。如果监视器不同,则您不会得到与关系的同步,因此,您不会得到发生在关系之前(从17.4.5开始):

如果动作x与后续动作y同步,那么我们还有hb(x,y)


因此,您的更新将按顺序执行,可能会丢失更新。

内存可见性是否取决于使用哪个监视器是。

锁B是在锁A被释放后获取的,它对内存可见性是否足够编号

两个线程必须在同一个监视器上同步,才能看到彼此的写入。在您的示例中,两个线程都可以看到
state
的值为
1
。无论你插入什么睡眠间隔。当然,这取决于您正在使用的JVM的实现,不同的JVM可能会产生不同的结果。基本上,您对字段的访问是不同步的,应该避免这种情况(因为它不确定
state
的值是什么)


请阅读Java规范中关于的优秀章节中的更多内容。

内存可见性是否取决于所使用的监视器是。

锁B是在锁A被释放后获取的,它对内存可见性是否足够编号

两个线程必须在同一个监视器上同步,才能看到彼此的写入。在您的示例中,两个线程都可以看到
state
的值为
1
。无论你插入什么睡眠间隔。当然,这取决于您正在使用的JVM的实现,不同的JVM可能会产生不同的结果。基本上,您对字段的访问是不同步的,应该避免这种情况(因为它不确定
state
的值是什么)


请阅读Java规范中关于的优秀章节中的更多内容。

发生在之前的关系是二进制的,即仅在两个事件之间。但它是可传递的。如果A发生在B之前,则只能从B获得A的内存可见性。@selig,但是
Thread.sleep
add
before
关系是否存在?否-如JLS中所述,无论
sleep
还是
Yield
都没有同步语义,即参与before-before关系。before-before关系是二进制的,即仅在两个事件之间。但它是可传递的。如果A发生在B.@selig之前,您只能从B获得A的内存可见性,但是
Thread.sleep
add
发生在
关系之前?否-如JLS中所述,
sleep
Yield
都没有同步语义,即参与到发生在关系之前。这有点奇怪。据我所知,有两种内存类型,线程本地(寄存器、处理器缓存等)和全局内存。在锁获取时,清除本地内存并从全局内存读取值;在锁释放时,将本地内存刷新到全局内存。您能否解释一下,如果状态被刷新到全局内存(
A
release)中,然后被强制读取(B获取),或者本地内存在锁释放时未刷新到全局内存,而在锁本地内存中(对线程释放的锁和将获取锁的线程可见),为什么状态可能不可见基本上是因为这两个线程没有建立“先发生后发生”的关系。因此JVM不会“刷新”对主内存的更改,并且可以缓存本地版本。为什么它不应该缓存它?加速可能是巨大的,程序员没有表示希望两个线程进行写操作通信(即,由于缺少同步)。从
开始,当线程退出同步块作为释放相关监视器的一部分时,JMM要求将本地处理器缓存刷新到主内存。
看来锁释放应该总是刷新本地内存。如果是这样的话,我不知道
This process guarantees that when a variable is written by one thread during a synchronized block protected by a given monitor and read by another thread during a synchronized block protected by the same monitor, the write to the variable will be visible by the reading thread.