2017-05-09 56 views
1

刚刚看到的代码如果在main()中启动一个新线程,那么调用wait()不能阻塞主线程?

static class ThreadA extends Thread { 
    public ThreadA(String name) { 
     super(name); 
    } 

    @Override 
    public void run() { 
     synchronized (this) { 
      System.out.println(Thread.currentThread().getName() + " call notify()"); 
     } 
    } 
} 

public static void main(String[] args) throws InterruptedException { 
    ThreadA t1 = new ThreadA("t1"); 

    synchronized (t1) { 
     System.out.println("start: " + Thread.currentThread().getName()); 
     t1.start(); 

     t1.wait(); 
     System.out.println(" -- end -- "); 
    } 
} 

,输出是:

start: main 
t1 call notify() 
-- end -- 

为什么调用wait()的不阻塞主线程

+0

它阻塞主线程,但它以某种方式被释放。它可能与主线程是最后一个线程有关,因为t1会完成执行。 – matt

+0

但是,如果我只是在同步的bolck中调用wait,它会阻塞主线程。@ matt – chasel

+0

是的,主线程被阻塞,然后你的另一个线程运行,然后主线程由于某种原因而被唤醒。这就是为什么建议不要使用等待,因为可能会有虚假的唤醒。因此,while循环建议或“加入”的建议。 – matt

回答

1

你需要的是Thread.join()Object.wait()的目的是等待该对象的监视器锁定被另一个线程释放(使用Object.notify()Object.notifyAll())。

public static void main(String[] args) throws InterruptedException { 
    ThreadA t1 = new ThreadA("t1"); 

    synchronized (t1) { 
     System.out.println("start: " + Thread.currentThread().getName()); 
     t1.start(); 

     t1.join(); 
     System.out.println(" -- end -- "); 
    } 
} 
+0

这不是很奇怪,在这个例子中'notify'被叫?线程通知完成后是否通知?它是否与离开同步块有关? – matt

+0

我只想知道为什么主线程不阻塞,据我所知,除非调用notify/notifyAll,当前线程会在wait()后阻塞 – chasel

+0

等待和连接有不同的使用目的。加入将等到中断或加入线程运行阻塞完成。但是,当一个非法的人得到时,等待结束。没有异常抛出,程序员知道有不同的线程状态。 –

2

的回答你的问题可以在join(long millis)方法的javadoc中找到:

此实现使用this.wait电话空调上this.isAlive的循环。 由于线程终止this.notifyAll方法被调用。建议应用程序不要在Thread实例上使用wait,notify或notifyAll。

(重点煤矿)

所以:你的主循环将停止等待,因为它的线程在等待对自己的呼叫notifyAll因为它完成。

正如其他人已经指出的那样,等待线程完成的正确方法是致电join

+0

非常感谢你 – chasel