大飞老师带你再看Java线程(五)

本篇来聊下线程合并-join:

概念

join字面上解释是加入/合并/连接的意思, 而api给出的解释:

   /**
     * Waits for this thread to die.
   */

在没有了解join方法功能前,“等当前线程死亡”,这解释有点蛋疼。这里先不解释,看案例:

public class App {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new Runnable() {
            public void run() {
                try {
                    //睡2s
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("这是子线程..." + Thread.currentThread().getName());
            }
        }, "t1");

        //启动子线程
        t1.start();
        //t1.join();
        //打印主线程
        System.out.println("这是主线程....main");
    }
}

运行后结果:在注释掉 t1.join() 方法时,打印结果

这是主线程....main
这是子线程...t1

如果解开t1.join() 方法注释时,打印结果
注意:t1.join必须在start调用后执行,否则没意义

这是子线程...t1
这是主线程....main

问题:2次操作,一个没有t1.join, 一个有t1.join, 打印的结果是相反的,为何?
答案:
join按照开篇的描述,其他都表示同一个意思,描述问题角度不一样而已。

合并:将t1线程合并到main线程中

main线程运行到t1.join方法时,会先阻塞,将cpu执行权交给t1,等待t1执行完毕,再获取CPU执行剩下的功能。居于这点,可以认为将t1线程执行的逻辑加入到main线程中执行,或者说将t1线程合并到main线程中执行。

等死:等待t1线程终止

跟合并解释一样,可以这么认为:main线程等t1线程执行完毕之后再执行。 也即等t1线程终止后再执行:Waits for this thread to die.

常见的api

thread.join(); //表示等待thread线程逻辑执行完毕 。
thread.join(1000); //表示等待thread线程1毫秒, 操作1毫秒,不再等待。

join实现原理

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;
            }
        }
    }
分析

上面源码, join方法是synchronized修饰的方法, 当main线程调用 t1.join()进入join方法后,main线程马上获取到t1对象锁,接着进入到millis ==0这个分支, 执行wait(0) 方法, 当前线程也即主线程立马挂起, 在不被唤醒前提下, wait(0) 表示无线等待.

疑问

主线程调用wait(0), 已经阻塞了, 当t1线程执行完毕后, 为什么没有notify/notifyAll页面自动醒来,完成后续任务呢?

答案:其实线程执行完毕之后, jvm会线程进行收尾工作, 会唤醒该线程对象锁中阻塞的所有线程.如果想了解更加详细: 传送门


猜你喜欢

转载自blog.csdn.net/wolfcode_cn/article/details/80900923
今日推荐