【线程基础】【四】join()方法详解
1 前言
看了wait()
方法之后,我们再来讲讲join()
方法,因为join()
方法就是通过wait()
方法实现的。
2 含义
让主线程等待(WAITING状态),一直等到其他线程不再活动为止。join在英语中是“加入”的意思,join()
方法要做的事就是,当有新的线程加入时,主线程会进入等待状态,一直到调用join()
方法的线程执行结束为止。
join用法示例:
public static void main(String[] args) { Runnable runnable = new Runnable() { @Override public void run() { System.out.println("子线程执行"); } }; Thread thread1 = new Thread(runnable); Thread thread2 = new Thread(runnable); thread1.start(); thread2.start(); try { //主线程开始等待子线程thread1,thread2 thread1.join(); thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } //等待两个线程都执行完(不活动)了,才执行下行打印 System.out.println("执行完毕"); }
代码会在thread1和thread2执行完后,才会执行System.out.println("执行完毕")
;
3 源码
join()
方法代码是通过java代码实现的,代码如下:
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) { // 关键实现在此行,通过wait方法永久等待。 while (isAlive()) { wait(0); } } else { while (isAlive()) { long delay = millis - now; if (delay <= 0) { break; } wait(delay); now = System.currentTimeMillis() - base; } } }
join()方法的等效写法:
thread1.join(); thread2.join(); // 可以替换为: while (thread1.isAlive() || thread2.isAlive()) { //只要两个线程中有任何一个线程还在活动,主线程就不会往下执行 }
join()方法是用wait()
方法实现,但为什么没有通过notify()
系列方法唤醒呀,如果不唤醒,那不就一直等待下去了吗?
原因是:在java中,Thread类线程执行完run()方法后,一定会自动执行notifyAll()方法即Thread类线程执行完run()方法后,一定会自动执行notifyAll()方法,这个细节隐藏在Java的Native方法中,所以一般不会被人发现。我们观察C/C++源码,如下:
oid JavaThread::exit(booldestory_vm, ExitTypeexit_type); static void ensure_join(JavaThread*thread) { Handle threadObj(thread, thread -> threadObj()); ObjectLocker lock(threadObj, thread); thread -> clear_pending_exception(); java_lang_Thread::set_thread_status(threadObj(), java_lang_Thread::TERMINATED); java_lang_Thread::set_thread(threadObj(), NULL); //下行执行了notifyAll()操作 lock.notify_all(thread); thread -> clear_pending_exception(); }
其中ensure_join
就是执行join()方法,等方法执行结束时,此行代码lock.notify_all(thread);
意思是通过notifyAll()
唤醒了所有等待线程。所以在使用线程的时候,要特别注意。
4 小结
好啦,关于join方法就看到这里,实际调用的是wait方法,有理解不对的地方欢迎指正哈。