Thread.Join源码解读

Thread.join() 和 Object.wait( )方法思考

先看这个例子:在main线程里面,创建了一个新的线程sonThread,要求 son线程执行完之后,再执行join后面的代码

    public static void main(String[] args) {
        Thread sonThread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(30000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(" A END");
            }
        },"newThread");
        sonThread.start();

        try {
            sonThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("main end");
    }

这行代码最终会输出

 A END
main end

我们要研究的就是 join方法为何会阻塞住 main线程,直到 son线程执行完成。

join源码

    public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;
        ...
        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        }
        ...
    }

join方法的追踪很简单,最终是指向 Thread#join(0)方法,因为 millis ==0 成立,所以关键的代码就在 while (isAlive())判断,和里面的wait(0)方法。

Thread#isAlive() 方法

这是一个native方法,用来判断当前线程是否存活,这里的 isAlive 判断的是调用 isAlive()方法的Thread对象,而并不是当前线程
结合上面的例子:上面是由 sonThread.join( ) 方法进入,所以,isAlive判断的是sonThread 这个对象,并不是main线程,我曾经错误认为,isAlive判断的是main线程。
这里需要注意: sonThread对象在创建后,是存在于jvm中,在调用 sonThread.start( ) 方法后,由JVM(用户态)向系统os申请创建一个线程(内核态),然后 jvm中的这个线程对象会和 os 创建好的线程进行绑定。 os创建好的线程会去调用 JVM对象中的run方法。
也就是:
1.jvm创建线程对象,此时为用户态;
2.线程对象.start() 方法,jvm(C++代码)向操作系统申请,创建一个内核级别的线程,此时有用户态向内核态切换,即人们常说的创建线程的成本。
3.完成绑定。
4.os的线程去 call JVM中线程对象的 run 方法。

完成了这样的区分后,就清楚了, sonThread.alive( )方法返回true的时候,表示sonThread所绑定的线程处于任务中,则进入 wait(0)

Objecte#wait(0)

wait(0)方法是 Thread类继承自 Object的方法,此时,我强烈建议把关注点从 Thread类移开,清楚区分,这是Object类提供的 wait方法,它表示,让持有 object对象的线程释放 object的锁,并阻塞住这个线程

         while (isAlive()) {
                wait(0);
            }

在这行代码里,wait(0)的方法是被 sonThread这个对象调用,所以this指的是sonThread这个对象,持有这个sonThread对象的是 main线程。
main线程释放 sonThread这个对象的锁(注意,join方法是 syn修饰的,这表示,进入wait(0)代码时,当前线程必定是已经获取了 sonThread对象的锁,先获取,再释放,这是jvm规范)。释放后,就处于阻塞状态,等待唤醒。

main何时被唤醒

这里借用一下这篇文章https://blog.csdn.net/u010983881/article/details/80257703,在jvm源码里,线程执行完后有一个ensure_join,会唤醒阻塞在这个线程对象上的其他线程。

static void ensure_join(JavaThread* thread) {
    // We do not need to grap the Threads_lock, since we are operating on ourself.
    Handle threadObj(thread, thread->threadObj());
    assert(threadObj.not_null(), "java thread object must exist");
    ObjectLocker lock(threadObj, thread);
    // Ignore pending exception (ThreadDeath), since we are exiting anyway
    thread->clear_pending_exception();
    // Thread is exiting. So set thread_status field in  java.lang.Thread class to TERMINATED.
    java_lang_Thread::set_thread_status(threadObj(), java_lang_Thread::TERMINATED);
    // Clear the native thread instance - this makes isAlive return false and allows the join()
    // to complete once we've done the notify_all below
    java_lang_Thread::set_thread(threadObj(), NULL);

    // 同志们看到了没,别的不用看,就看这一句
    // thread就是当前线程,是啥?就是刚才例子中说的threadA线程啊。
    lock.notify_all(thread);

    // Ignore pending exception (ThreadDeath), since we are exiting anyway
    thread->clear_pending_exception();
}

wait(0)时,main线程释放了 sonThread这个线程对象的锁,并阻塞在sonThread这个线程对象上,当sonThread锁绑定的线程执行完后,又会唤醒 main线程,所以,wait(0)这行代码执行完成,此时,重新回到 while()循环,即

        while (isAlive()) {
                wait(0);
            }

这块循环中,此时 sonThread所绑定的os线程已经完成了任务,不再活跃,sonThread.isAlive也就返回false,跳出while()循环,join方法执行完成,main线程得到继续执行,最终完成。

这就是 join能够产生阻塞的原理。
总结如下:
1.main线程创建新的线程对象 sonThread;
2.sonThread.start() 完成os线程创建和绑定,os线程开始异步执行。
3.sonThread.join(),进入到 while(isAlive())循环判断,只要 sonThread对象所绑定的os线程处于存活状态,sonThread.isAlive就会返回true,进入wait(0)。
4.sonThread.wait(0),会让持有sonThred对象的线程阻塞,join方法是syn方法,调用这个join方法的线程释放锁,并一直阻塞,直到被唤醒。
5.sonThread所绑定的os线程在执行完后,会唤醒阻塞在sonThread对象上的线程,这些线程会再次活跃起来,尝试获取sonThread对象的锁。
6.阻塞结束,完成目的。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容