会在同步语句之前出现在另一个同步错误之前吗?

时间:2018-10-30 16:10:09

标签: java multithreading

如果有两个全局无变量int变量a,b和object obj;线程1具有:

 1 ++a;
 2 synchronized(obj){
 3   ++b; 
 4 }
 5 print a

Thead 2具有:

 1 synchronized(obj){
 2   ++b; 
 3 }
 4 print a

所以我的问题是:

1,1号代码可以在线程1中的4行代码之后重新排序吗?

2,如果线程1首先锁定obj的锁,则线程2进行;因此线程2将在a时正确获得print a

3 个答案:

答案 0 :(得分:2)

Java语言规范中定义的以下规则适用于您的代码:

  

17.4.4. Synchronization Order

     

同步动作在动作上产生 synchronized-with 关系,定义如下:

     
      
  1. 监视器m上的解锁操作m上的所有后续 lock 操作(与“ ”同步),其中“后续”是根据同步顺序定义的。
  2.   

<-->

  

17.4.5. Happens-before Order

     

两个动作可以通过 happens-before 关系进行排序。如果一个动作先于另一个,则第一个动作对第二个动作可见,并且在第二个动作之前

     

如果我们有两个动作xy,则我们写hb(x, y)来表示x 发生之前 y

     
      
  1. 如果xy是同一线程的动作,并且x按程序顺序位于y之前,则hb(x, y)。 p>

  2.   
  3. 如果操作x 与后续操作y同步,那么我们也有hb(x, y)

  4.   
  5. 如果hb(x, y)hb(y, z),则为hb(x, z)

  6.   

现在,将其应用于您的代码:

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)之间没有先发生关系,因此结果是不可预测的。


如果线程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首先锁定obj对象,则线程2这样做;这样,当打印a时,线程2将正确获得a。

是的,如果线程1首先锁定,则线程2将打印更新后的值a,请参见上文。

答案 1 :(得分:1)

在同步块之前,之中或之后的语句无法跨这些边界重新排序。这些语句可以重新排序,它们也位于这些边界的同一侧。

  

如果这些字段都不是可变的,则所有投注均关闭。

这是没有同步的情况,但是,同步也会引入全部的内存障碍。

  

线程1中的4行代码之后,1行代码可以重新排序吗?

不能将其订购到第2行之后。

  

如果线程1首先锁定obj对象,则线程2这样做;这样,线程2在打印a时将正确获得a值。

提供的线程1在线程2之前进入synchronized。但是,线程2可能首先执行,在这种情况下,它可能会看到旧值。

答案 2 :(得分:0)

请参见https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4.5上的“发生订单之前”部分。

  

在监视器上进行的每个后续锁定之前,发生监视器上的解锁。

这意味着,如果线程B获取了监视器(通过进入同步块),它将在释放监视器之前(即在同步块内和之前)对线程A所做的一切具有可见性。

对于问题1:打印的数字始终是递增值(程序顺序保留在线程A中)

对于问题2:线程B具有a的更新值的可见性,因为它们是有序的:线程A更新a>线程A释放监视器>线程B获取监视器>线程B读取a