synchronized关键字是否会阻止Java中的重新排序?

use*_*989 8 java multithreading synchronized

假设我在Java中有以下代码

a = 5;
synchronized(lock){
    b = 5;
}
c = 5;
Run Code Online (Sandbox Code Playgroud)

同步是否会阻止重新排序?a,b和c之间没有依赖关系.分配给第一个然后发生到b然后发生到c?如果我没有同步,那么语句可以以JVM选择的任何方式重新排序吗?

dca*_*tro 6

将赋值锁定为bwill,至少会在赋值之前引入获取栅栏,并在赋值之后引入释放栅栏.

这可以防止在获取栅栏移动到栅栏上方之后的指令,以及释放栅栏之前的指令移动到栅栏下方.

使用↓↑表示法:

a = 5;
? 
b = 5;
?
c = 5;
Run Code Online (Sandbox Code Playgroud)

↓可防止指令在其上方移动.↑可以防止指令移动到它下面.


Pet*_*rey 5

同步是否会阻止重新排序?

它可以防止某些重新排序。您仍然可以在同步块外部和同步块内部进行重新排序,但不能从同步块内部到外部进行重新排序。

a、b、c之间不存在依赖关系。

这没有什么区别。

是否会先分配给 a,然后分配给 b,然后分配给 c?

是的。但正如已经指出的,并不能保证所有 JVM 都能做到这一点。(见下文)

如果我没有同步,语句可以以 JVM 选择的任何方式重新排序吗?

是的,由 JVM 和/或 CPU 指令优化器和/或 CPU 缓存执行,但不太可能,因为没有明显的理由怀疑更改 a = 5; 的顺序。b = 5;将提高性能。

您可以看到缓存可见性的变化。即读取这些值的另一个线程可以看到 b = 5;a = 5 之前;例如,如果它们没有同步,则它们位于不同的缓存行上。

  • 据我所知,这是错误的。我们可以将尽可能多的额外写入/读取*放入*同步块中,并根据内部的正常规则重新排序。我们只需要确保监视器的后续锁定和解锁之间的 hb 关系不被违反 - 即使我们重新排序所有三个写入(只要保证在解锁后下一个锁定线程)看到“a = 5; b=5”) (4认同)