我有一个关于
Java内存模型的问题.给出以下示例:
action 1 action 2 synchronized(monitorObject) { //acquire action 3 } //release action 4
获取和释放可以是任何与边缘同步的(锁定,解锁,启动线程,连接线程,检测线程中断,易失性写入,易失性读取等)
是否保证在收购之前无法移动动作3,在发布后不能移动?
并且保证行为2在获得后不能移动(既不在释放之前也不在释放之后),并且动作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块中,则可能会导致死锁:
y = 0; synchronized(syncB) { y = 1; synchronized(syncA) { x = 1; } }
我认为这不是一个合法的编译器转换,因为它会改变同步顺序.我有这个假设吗? Java内存模型(JMM)的哪一部分允许/禁止这一点?
解决方法
感谢
assylias链接到
this question,其中包含从
JSR-133 Cookbook的这个图像的答案:
根据这个图像,编辑器从EDIT 3转换是非法的,因为它重新排列两个MonitorEnters.
此外,该表还显示了哪些同步边缘是什么样的“重新排序障碍”,为其他操作.
感谢您的帮助 :)