Java Thread.join()等待线程

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

定义

join()throws InterruptedException;  //无参数的join()等价于join(0),作用是一直等待该线程死亡

join(long millis, int nanos) throws InterruptedException;  //最多等待该线程死亡millis毫秒

join(long millis, int nanos) throws InterruptedException ; //最多等待该线程死亡millis毫秒加nanos纳秒

源码

public final void join() throws InterruptedException {
    join(0L);//后面参数为wait的最大时间,如果是0表示永远等待直到该线程执行完毕
}
public final synchronized void join(long millis) //参数millis为0.  
throws InterruptedException {
    long base = System.currentTimeMillis();
    long now = 0;
    if (millis < 0) {
        throw new IllegalArgumentException("timeout value is negative");
    }
    if (millis == 0) { //进入这个分支  
        while (isAlive()) { //判断本线程是否为活动的。这里的本线程就是t1.  
            wait(0); //阻塞  
        }
    } else {
        while (isAlive()) {
            long delay = millis - now;
            if (delay <= 0) {
                break;
            }
            wait(delay);
            now = System.currentTimeMillis() - base;
        }
    }
}

例子

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);
            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();阻塞处起动,向下继续执行的结果。

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

总结

1. 在Java多线程中,如果某一个线程s在另一个线程t上调用t.join(),此线程s将被挂起,直到目标线程t结束才恢复(此时t.isAlive()返回为假)。也可以在调用join()时带上一个超时参数(单位可以是毫秒,或者毫秒和纳秒),这样如果目标线程在这段时间内还没有结束的话,join()方法总能返回。对join()方法的调用可以被中断,做法是在调用线程上调用interrupt()方法。

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


版权声明:本文为JAVASCHOOL原创文章,未经本站允许不得转载。