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
addbefore
关系是否存在?否-如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.