博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java Thread.join()方法
阅读量:6670 次
发布时间:2019-06-25

本文共 4743 字,大约阅读时间需要 15 分钟。

hot3.png

join方法只有在继承了Thread类的线程中才有。

线程必须要start() 后再join才能起作用。

1. 使用方式

join是Thread类的一个方法,启动线程后直接调用。

2. 为什么使用join方法

在很多情况下,主线程生成并启动了子线程,如果子线要进行大量的耗时运算,主线程往往先于子线程结束,但是如果主线程处理完其他的事务后,需要用到子线程的处理结果,也就是主线程需要等待子线程执行完之后再结束,这个时候就用join方法。

换句话说将另外一个线程join到当前线程,则需要等到join进来的线程执行完才会继续执行当前线程。join来者是客,让客人先执行完

3. join方法的作用

在JDK文档里,JAVA对join方法的描述是:

join 

public final void join() throws InterruptedException Waits for this thread to die. Throws: InterruptedException  - if any thread has interrupted the current thread. The interrupted status of the current thread is cleared when this exception is thrown.

也就是说,join的作用是等待该线程终止,这里需要理解的就是该线程是指主线程等待子线程的终止。也就是在子线程调用了join方法后面的代码,只有等到子线程结束了才能执行。

4. 实例说明

class BThread extends Thread {    public BThread() {        super("[BThread] Thread");    };    public void run() {        String threadName = Thread.currentThread().getName();        System.out.println(threadName + " start.");        try {            for (int i = 0; i < 5; i++) {                System.out.println(threadName + " loop at " + i);                Thread.sleep(1000);            }            System.out.println(threadName + " end.");        } catch (Exception e) {            System.out.println("Exception from " + threadName + ".run");        }    }}class AThread extends Thread {    BThread bt;    public AThread(BThread bt) {        super("[AThread] Thread");        this.bt = bt;    }    public void run() {        String threadName = Thread.currentThread().getName();        System.out.println(threadName + " start.");        try {            bt.join();            System.out.println(threadName + " end.");        } catch (Exception e) {            System.out.println("Exception from " + threadName + ".run");        }    }}public class TestDemo {    public static void main(String[] args) {        String threadName = Thread.currentThread().getName();        System.out.println(threadName + " start.");        BThread bt = new BThread();        AThread at = new AThread(bt);        try {            bt.start();            Thread.sleep(2000);//确保bt线程启动            at.start();            at.join();        } catch (Exception e) {            System.out.println("Exception from main");        }        System.out.println(threadName + " end!");    }}

打印结果为:

main start.    //主线程起动,因为调用了at.join(),要等到at结束了,此线程才能向下执行。 [BThread] Thread start. [BThread] Thread loop at 0 [BThread] Thread loop at 1 [AThread] Thread start.    //线程at启动,因为调用bt.join(),等到bt结束了才向下执行。 [BThread] Thread loop at 2 [BThread] Thread loop at 3 [BThread] Thread loop at 4 [BThread] Thread end. [AThread] Thread end.    // 线程AThread在bt.join();阻塞处起动,向下继续执行的结果 main end!      //线程AThread结束,此线程在at.join();阻塞处起动,向下继续执行的结果。

那我们修改一下代码:

 

public class TestDemo {    public static void main(String[] args) {        String threadName = Thread.currentThread().getName();        System.out.println(threadName + " start.");        BThread bt = new BThread();        AThread at = new AThread(bt);        try {            bt.start();            Thread.sleep(2000);            at.start();            //at.join(); //在此处注释掉对join()的调用        } catch (Exception e) {            System.out.println("Exception from main");        }        System.out.println(threadName + " end!");    }}

结果为:

main start.    // 主线程起动,因为Thread.sleep(2000),主线程没有马上结束;[BThread] Thread start.    //线程BThread起动[BThread] Thread loop at 0[BThread] Thread loop at 1main end!   // 在sleep两秒后主线程结束,AThread执行的bt.join();并不会影响到主线程。[AThread] Thread start.    //线程at起动,因为调用了bt.join(),等到bt结束了,此线程才向下执行。[BThread] Thread loop at 2[BThread] Thread loop at 3[BThread] Thread loop at 4[BThread] Thread end.    //线程BThread结束了[AThread] Thread end.    // 线程AThread在bt.join();阻塞处起动,向下继续执行的结果

5. 从源码看join方法

在AThread的run方法里,执行了bt.join(); 进入看一下它的JDK源码:

public final void join() throws InterruptedException {    join(0L);}

然后进入join(0L)方法:

public final synchronized void join(long l)    throws InterruptedException{    long l1 = System.currentTimeMillis();    long l2 = 0L;    if(l < 0L)        throw new IllegalArgumentException("timeout value is negative");    if(l == 0L)        for(; isAlive(); wait(0L));    else        do        {            if(!isAlive())                break;            long l3 = l - l2;            if(l3 <= 0L)                break;            wait(l3);            l2 = System.currentTimeMillis() - l1;        } while(true);}

单纯从代码上看:

* 如果线程被生成了,但还未被起动,isAlive()将返回false,调用它的join()方法是没有作用的。将直接继续向下执行。

* 在AThread类中的run方法中,bt.join()是判断bt的active状态,如果bt的isActive()方法返回false,在bt.join(),这一点就不用阻塞了,可以继续向下进行了。从源码里看,wait方法中有参数,也就是不用唤醒谁,只是不再执行wait,向下继续执行而已。

* 在join()方法中,对于isAlive()和wait()方法的作用对象是个比较让人困惑的问题: 

isAlive()方法的签名是:public final native boolean isAlive(),也就是说isAlive()是判断当前线程的状态,也就是bt的状态。

 

转载于:https://my.oschina.net/hunglish/blog/747552

你可能感兴趣的文章
Redis实现广告缓存、并完善缓存击穿
查看>>
如何绘制最美的鱼骨图?
查看>>
什么是session?什么是cookie?session和cookie有什么区别?
查看>>
javascript引擎执行的过程的理解--语法分析和预编译阶段
查看>>
百度正式发布PaddlePaddle深度强化学习框架PARL
查看>>
迟到但重要的事
查看>>
Node.js 指南(不要阻塞事件循环或工作池)
查看>>
2018年第40周-scala入门-工具使用
查看>>
微信小程序快速入门分享大纲
查看>>
form中只有一个input时自动提交问题
查看>>
面试官:说说快速失败和安全失败是什么
查看>>
node.js中常用的fs文件系统
查看>>
Java抽象类与接口的区别
查看>>
在vue项目中使用vuex
查看>>
服务器从零开始(1D)-user+sudo+vnc
查看>>
一张图让自己搞懂(mēng)原型&原型链
查看>>
Mybatis N+1问题解析
查看>>
前端每日实战:75# 视频演示如何用纯 CSS 创作一支摇曳着烛光的蜡烛
查看>>
我为什么要升级到Ionic3
查看>>
Elixir: 函数装饰器
查看>>