java - 与边缘同步的编译器是否在两个方向上重新排序障碍?

标签 java multithreading compiler-optimization memory-model java-memory-model

我有一个关于 Java 内存模型的问题。给定以下示例:

action 1
action 2
synchronized(monitorObject) { //acquire
    action 3
} //release
action 4

acquirerelease 可以是任何同步边缘(锁定、解锁、启动线程、加入线程、检测线程中断、volatile-write、volatile-read、等等)

是否保证action 3在获取之前不能移动并且在释放之后不能移动? p>

是否保证 action 2 不能在获取之后(无论是在发布之前还是发布之后)和action 4 不能在发布之前移动(无论是在获取之前还是之后)?

对于编译器的重新排序操作,与边同步的“双向障碍”也是如此吗?


编辑 1 我很担心这一点,因为如果与边缘同步不是双向重新排序障碍,编译器可以通过将锁获取转移到其他人来简单地创建死锁。

或者甚至不需要双向重新排序障碍来防止这种情况发生,因为无法将锁获取插入其他人,因为这会改变同步顺序?


编辑 2 操作 1、2、3 和 4 是 JMM 定义的“线程间操作” .


编辑 3 下面是一个显示重新排序如何导致死锁的示例:

x 和 y 是共享变量,syncA 和 syncB 可以被任何其他线程获取。但是使用下面的代码,就不可能出现死锁。

/* 1 */  synchronized(syncA) {
/* 2 */      x = 1;
/* 3 */  }
/* 4 */  y = 0;
/* 5 */  synchronized(syncB) {
/* 6 */      y = 1;
/* 7 */  }

但是,如果对 syncA 的获取被重新排序到 syncB block 中,这可能会导致死锁:

y = 0;
synchronized(syncB) {
    y = 1;
    synchronized(syncA) {
        x = 1;
    }
}

我认为这不是合法的编译器转换,因为它会改变同步顺序。我对这个假设是否正确? Java 内存模型 (JMM) 的哪一部分允许/不允许这样做?

最佳答案

感谢assylias链接到 this question其中包含来自 JSR-133 Cookbook 的这张图片的答案:

Reordering Rules Table

根据这张图片,EDIT 3 的编译器转换是非法的,因为它重新排序了两个 MonitorEnter

此外,此表还显示了哪些同步边是哪些类型的“重新排序障碍”以及其他操作。

谢谢你的帮助:)

关于java - 与边缘同步的编译器是否在两个方向上重新排序障碍?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26724443/

相关文章:

java - 从项目中删除静态

java - 扩展 java 类的同时也改变它

linux - c++11 线程池在 windows 上工作-在 linux 上是 block

java - JVM 线程转储包含不锁定线程的监视器

compiler-optimization - 编译器代码生成——条件 block 内的寄存器分配

java - 如何在不折叠的情况下将 ExpandableListView 放入 ScrollView?

java - 如何中断已发布的 Flowable

c# - 在 ASP.net 中使用静态方法进行安全验证是不明智的吗?

haskell - 为什么需要 Data.Text.Lazy?编译器优化器不能创建严格的惰性结构 block 吗?

c++ - 具有递归模板参数包函数是否为每次迭代创建特定函数?