简介
join()是Thread类的一个方法。t.join()方法阻塞调用此方法的线程(calling thread),直到线程t完成,此线程再继续执行;通常用于在main()主线程内,等待其它线程完成再结束main()主线程。
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public static void main(String[] args){ Thread threadA = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(1000); } catch (Exception e) { e.printStackTrace(); } System.out.println("threadA run"); } }); threadA.start(); try { threadA.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("MainThread run finished."); }
|
在main主线程调用threadA.join()后,threadA线程正常运行,main主线程会等待threadA线程结束后再继续运行。
原理分析
下面看下join()的源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| public final void join() throws InterruptedException { join(0); }
public final synchronized void join(long millis) throws InterruptedException { long base = System.currentTimeMillis(); long now = 0;
if (millis < 0) { throw new IllegalArgumentException("timeout value is negative"); }
if (millis == 0) { while (isAlive()) { wait(0); } } else { while (isAlive()) { long delay = millis - now; if (delay <= 0) { break; } wait(delay); now = System.currentTimeMillis() - base; } } }
public final synchronized void join(long millis, int nanos) throws InterruptedException {
if (millis < 0) { throw new IllegalArgumentException("timeout value is negative"); }
if (nanos < 0 || nanos > 999999) { throw new IllegalArgumentException( "nanosecond timeout value out of range"); }
if (nanos >= 500000 || (nanos != 0 && millis == 0)) { millis++; }
join(millis); }
|
这里使用synchronized是因为在join()里面调用了wait(),此时要进入join(long millis)方法必须持有threadA线程对象锁,也就是主线程持有了threadA这个对象的锁。
下面重点看这一块的代码
1 2 3
| while (isAlive()) { wait(0); }
|
如果threadA线程是活跃的,则循环调用threadA.wait(0),此时正在执行的线程(main主线程)释放threadA线程的对象锁,其他线程可以竞争锁并进入threadA.join(0)。一旦threadA线程执行完毕(状态为TERMINATED),JVM会调用lock.notify_all(thread),唤醒持有threadA这个对象锁的线程,至此阻塞在threadA对象上的线程,即主线程可以继续执行后面的内容。
总结
join()方法的底层是通过wait() 实现的。当main主线程调用threadA.join()时,main线程会获得threadA线程对象锁,只有这样才能执行synchronized join()方法内,调用threadA线程对象的wait()。目的是让持有这个threadA线程对象锁的线程都进入等待,等待threadA线程执行完毕。然后JVM底层lock.notify_all(thread),唤醒持有threadA对象锁的所有线程。
参考资料