-2

谁能帮我解决以下问题?

public class Starter extends Thread{
   private int x=2;
   public static void main(String[] args) throws Exception{
      new Starter().makeItSo();
   }
   public Starter(){
      x=5;
      start(); 
   }
   public void makeItSo() throws Exception {
      join();
      x=x-1;
      System.out.println(x);
   }
   public void run(){x*=2;}
}

A. 4

B. 5

C. 8

D. 9

E. 编译失败

F. 运行时抛出异常

G. 无法确定

在转储中,答案是 D。我知道在 new Starter().makeItSo 中创建了一个新线程。但是谁能告诉我为什么 run() 中的 x*=2 在方法 makeItSo 中的 x=x-1 和 System.out.println(x) 之间执行?

4

1 回答 1

1

但是谁能告诉我为什么 run() 中的 x*=2 在方法 makeItSo 中的 x=x-1 和 System.out.println(x) 之间执行

这不是发生的事情。以下是发布的代码中发生的情况的解释:

1) 主线程创建一个 Starter 类型的新对象,首先将其实例变量 x 初始化为 2(变量初始化),然后(在构造函数中)将相同的实例变量设置为 5,并启动新线程。

2)主线程调用方法makeItSo(在构造函数调用创建的Starter实例上)并加入新线程,等待它完成。

3) 新线程执行它的 run 方法,将 x 加倍,然后完成(通知主线程它已经完成)。

4) 然后主线程唤醒,从 x 中减去 1,并打印 9。

由于 x 是跨线程修改的,并且不是易失性或原子性的,并且不执行同步,因此新线程对 x 的更新保证对主线程可见并不明显(因此无论它是有意工作还是通过事故不清楚),使 G 看起来像是正确的答案。但是 join 会在新线程上进行同步(因为 join 是使用等待实现的,因此会锁定线程);x 的当前值将在主线程从 join 调用返回时可见。所以答案是D。

于 2015-10-22T20:52:20.340 回答