我对Java内存模型有疑问。给出以下示例:
action 1
action 2
synchronized(monitorObject) { //acquire
action 3
} //release
action 4
acquire
和release
可以是任何同步边缘(锁定,解锁,启动线程,连接线程,检测线程中断,volatile-write,volatile-read等)。
是否可以确保{<1}}在获取之前无法移动 之后无法移动?
并且保证{<1}}在获取之后(在发布之前或之后)都无法移动并且action 3
无法移动 发布之前(获取之前或之后)?
对于编译器的重新排序操作,是否与边缘“双向障碍”同步?
编辑1 我担心这一点,因为如果同步 - 边缘不是双向重新排序障碍,编译器可以通过将锁获取移动到其他人来简单地创建死锁。
或者是双向重新排序障碍,甚至不需要阻止这种情况,因为锁定获取不能被推送到其他人,因为这会改变同步顺序?
编辑2 动作1,2,3和4是由JMM定义的“线程间动作”。
编辑3 这是一个示例,显示了重新排序如何导致死锁:
x和y是共享变量,syncA和syncB可以由任何其他线程获取。但是使用以下代码,可能没有死锁。
action 2
但是,如果将syncA的获取重新排序到syncB块中,则可能会导致死锁:
action 4
我认为这不是合法的编译器转换,因为它会改变同步顺序。我对这个假设是对的吗? Java内存模型(JMM)的哪个部分允许/禁止这个?
答案 0 :(得分:2)
感谢assylias链接到this question,其中包含来自JSR-133 Cookbook的此图片的答案:
根据这张图片,EDIT 3的编译器转换是非法的,因为它重新排序了两个 MonitorEnters 。
此外,此表显示哪些同步边缘是&#34; 重新排序屏障&#34;其他操作。
感谢您的帮助:)