Java 语言规范中定义的以下规则适用于您的代码:
17.4.4. Synchronization Order
同步动作在动作上产生synchronized-with关系,定义如下:
- 监视器
m 上的解锁 操作同步 m 上的所有后续锁定 操作(其中定义了“后续”根据同步顺序)。
17.4.5. Happens-before Order
两个动作可以通过 happens-before 关系进行排序。如果一个动作在另一个动作之前发生,那么第一个动作对第二个动作可见并排在第二个动作之前。
如果我们有两个动作x 和y,我们写hb(x, y) 表示x happens-before y。
-
如果x 和y 是同一线程的操作,并且x 在程序顺序中位于y 之前,则hb(x, y)。
-
如果一个动作x同步一个后续动作y,那么我们也有hb(x, y)。
-
如果hb(x, y) 和hb(y, z),那么hb(x, z)。
现在让我们将它应用到您的代码中:
A1 ++a;
A2 synchronized(obj){
A3 ++b;
A4 }
A5 print a
B1 synchronized(obj){
B2 ++b;
B3 }
B4 print a
规则 2 规定:
A1 -> A2 -> A3 -> A4 -> A5
B1 -> B2 -> B3 -> B4
结果取决于哪个线程首先到达synchronized 块。如果线程 B 先到达,就会出现问题,其中规则 1 + 3 状态:
B3 -> A2
综合:
A1 →→→→→→→→→→→→→ A2 → A3 → A4 → A5
↑
B1 → B2 → B3 →→→ B4
A1 (++a) 和 B4 (print a) 之间没有 happens-before 关系,因此结果无法预测。
如果线程 A 先到达,规则 1 + 3 状态:
B4 -> B1
合并
A1 → A2 → A3 → A4 →→→ A5
↓
→→ B1 → B2 → B3 → B4
规则 4 然后声明 hb(A1, A5) 和 hb(A1, B4),这意味着 ++a 保证发生在两个 print a 语句之前。
回答您的具体问题:
线程 1 中的 4 行代码之后可以重新排序 1 行代码吗?
在线程 1 中?没有。
从线程 2 中可以看出?是的,见上文。
如果线程 1 先 lock unlock obj ,那么线程 2 做;打印 a 时线程 2 也会正确获取 a 。
是的,如果线程 1 先锁定,线程 2 将打印 a 的更新值,见上文。