如何实现Thread类的join方法?

        从天圆地方到地球是圆的,从地心说到日心说,一个个思想模型的提出,都成功演奏了问题,假设,验证三部曲。所以我们就使用这些先哲留给我们的探索宇宙的思维方式——问题,假设,验证三部曲,来探究一下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”之前就算验证成功

运行结果:

如何实现Thread类的join方法?_第1张图片

可见这个假设验证成功


三部曲第二弹

问题

    通过这种不断循环判断的方式,可以实现让当前线程等待的功能,但是,线程会处于忙等待状态,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");
    }
}

如何实现Thread类的join方法?_第2张图片

    可见,通过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行,可见,源码当中正是这样实现的。

    我们的探索告一段落,下次再见!


参考资料:

    https://www.zhihu.com/question/44621343

你可能感兴趣的:(Java,线程)