从天圆地方到地球是圆的,从地心说到日心说,一个个思想模型的提出,都成功演奏了问题,假设,验证三部曲。所以我们就使用这些先哲留给我们的探索宇宙的思维方式——问题,假设,验证三部曲,来探究一下Java中Thread类的join方法到底是如何实现等待的。 |
---|
三部曲第一弹
问题
如何实现Thread.join()方法假设
一个最简单的实现方式,就是不断循环判断加入线程是否还在执行,直到停止运行,跳出循环,当前线程继续运行验证
public class MyThread extends Thread { /** * 自定义的join方法 */ public final void join2() { while (this.isAlive()) ; } @Override public void run() { try { sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("my thread run over"); } public static void main(String[] args) { MyThread myThread = new MyThread(); myThread.start(); myThread.join2(); System.out.println("main thread run over"); } }
在这个示例中,如果“my thread run over”打印在“main thread run over”之前就算验证成功
运行结果:
可见这个假设验证成功
三部曲第二弹
问题
通过这种不断循环判断的方式,可以实现让当前线程等待的功能,但是,线程会处于忙等待状态,CPU始终在空转,造成了不必要的性能开销
假设
通过调用wait方法,释放处理机,避免“忙等”状态
验证
public class MyThread extends Thread { /** * 自定义的join方法 */ public final void join2() { while (this.isAlive()) ; } /** * 自定义的join方法 * 可以释放CPU */ public final synchronized void join3() throws InterruptedException { while (this.isAlive()) { wait(); } } @Override public void run() { try { sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("my thread run over"); } public static void main(String[] args) throws InterruptedException { MyThread myThread = new MyThread(); myThread.start(); //myThread.join2(); myThread.join3(); System.out.println("main thread run over"); } }
可见,通过wait方法避免“忙等”是可行的
三部曲第三弹
问题
有wait,必有notify,可是在JDK中并不能找到对myThread线程的notify调用
假设
notify是jvm调用的
验证
jvm源码片段:
//一个c++函数: void JavaThread::exit(bool destroy_vm, ExitType exit_type); //这家伙是啥,就是一个线程执行完毕之后,jvm会做的事,做清理啊收尾工作, //里面有一个贼不起眼的一行代码,眼神不好还看不到的呢,就是这个:ensure_join(this); //翻译成中文叫 确保_join(这个);代码如下: 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); //同志们看到了没,别的不用看,就看这一句 //thread就是当前线程,是啥是啥?就是myThread线程啊。 lock.notify_all(thread); thread->clear_pending_exception(); }
所以,notify就是由jvm在线程执行结束后调用的
最后,再来看一下JDK的源码实现
以下是jdk_1.8.0.161中,java.lang.Thread类的源码片段:
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; } } }
仔细观察第二段源码中的第11、12行,可见,源码当中正是这样实现的。
我们的探索告一段落,下次再见!
参考资料: