线程的不可预测的行为

时间:2013-01-14 16:31:49

标签: java multithreading

任何人都可以解释为什么这个程序提供输出9?我猜测“不可预测的行为”作为答案,因为主线程和线程0可以按任何顺序执行。 join()会对主线程本身做什么?

public class Starter extends Thread{
    private int x = 2;
    public static void main(String[] args) throws Exception{
        new Starter().makeItSo();
    }

    public Starter(){
        //Thread main
        x=5;
        start();
    }

    public void makeItSo() throws Exception{
        //Thread main
        join();
        x = x-1;
        System.out.println(x);
    }

    public void run(){ 
        //Thread-0
        x*= 2;
        }
}

主线程启动thread-0并调用run方法。但如果你把SOP放在makeItSo()中,它会说主线程在调用join()之后在那里等待!为什么? 我认为makeItSo()或run()之间没有序列,所以X的值将是不可预测的。

4 个答案:

答案 0 :(得分:6)

此处的执行顺序是固定的,因为调用join()

  1. 构造函数设置x = 5
  2. 构造函数调用start,然后在新线程中调用run
  3. run执行x *= 5,使x等于10。
  4. makeItSo被调用。它会调用join,从而等待run结束。
  5. 最后,makeItSo设置x = x-1,使x等于9。

答案 1 :(得分:1)

为了真正深入理解这一点,您应该阅读java语言规范中的17.4.4 Synchronization Order,其中包含:

Synchronization actions induce the _synchronized-with_ relation on actions, 
defined as follows:   
         ...
 - An action that starts a thread _synchronizes-with_ the first action in the 
thread it starts.
         ...
 - The final action in a thread *T1* _synchronizes-with_ any action in another
thread *T2*  that detects that *T1* has terminated. *T2* may accomplish this 
by calling *T1.isAlive()* or *T1.join()*.

答案 2 :(得分:0)

首先创建Starter对象。在构造函数中,您有x = 5。比拨打start(),而内部呼叫run()。运行后你的x是10(x *= 2)。你的join()等待run()完成,之后你将x递减1,就是这样。 x是9.这里真的没什么不可预知的。

答案 3 :(得分:0)

我认为混淆是由调用join()的方式引起的 - 因为它是从实例方法调用的,就像在说this.join(),其中'this'引用在main中创建的Starter对象方法

这意味着主线程等待Starter线程终止,之后它会减少x的值。这是结果非常可预测的方式。