Java Thread.join()方法

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

线程必需要start() 后再join才能起做用。oop

1. 使用方式

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

2. 为何使用join方法

在不少状况下,主线程生成并启动了子线程,若是子线要进行大量的耗时运算,主线程每每先于子线程结束,可是若是主线程处理完其余的事务后,须要用到子线程的处理结果,也就是主线程须要等待子线程执行完以后再结束,这个时候就用join方法。spa

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

3. join方法的做用

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

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 1
main 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的状态。

相关文章
相关标签/搜索