一、使用方法
Thread t = new AThread(); t.start(); t.join();
二、为什么要使用 join()
方法
在很多情况下,主线程生成并启动了子线程,如果子线程里面要进行大量的耗时运算,主线程往往将结束于子线程之前。但如果主线程处理完其他事务之后,需要用到子线程的处理结果,也就是主线程需要等待子线程执行完成之后再结束,这个时候就需要用到join()
方法。
三、join()
方法的作用
JDK中对 join()
方法的解释为"Waits for this thread to die."
- "等待该进程结束",换句话说"当前进程等待子进程的终止",也就是在子线程中调用了join()
方法,当前线程需要等待子线程结束之后,才能执行join()
方法之后的代码。
四、实例解析
1、简单了解join()的用法:
public 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");
}
}
}
public 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(), 所以主线程要等到 AThread线程结束之后才能执行
[BThread] Thread start.
[BThread] Thread loop at 0
[BThread] Thread loop at 1
[AThread] Thread start. -- AThread线程启动, 因为AThread线程中调用了bt.join(), 所以AThread线程要等到BThread线程结束之后才能执行
[BThread] Thread loop at 2
[BThread] Thread loop at 3
[BThread] Thread loop at 4
[BThread] Thread end. -- BThread线程结束了, AThread线程执行
[AThread] Thread end. -- AThread线程结束了, 主线程执行
main end!
2、深入的了解join()
的用法:
网上有很多人是这样解释
join()
的用法的:“主线程等待子线程的终止 ”,相信有很多人都会这么说,但是这个说法是完全错误的,为什么呢?
请看例子,在上面代码的基础上,我们对TestDemo类做一下改动:
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. -- 主线程启动
[BThread] Thread start. -- BThread线程启动
[BThread] Thread loop at 0
[BThread] Thread loop at 1
main end! -- 主线程结束,(也就是说AThread线程中调用了bt.join()并不会影响到主线程)
[AThread] Thread start. -- AThread线程启动, 因为AThread线程中调用了bt.join(), 所以AThread线程要等到BThread线程结束之后才能执行
[BThread] Thread loop at 2
[BThread] Thread loop at 3
[BThread] Thread loop at 4
[BThread] Thread end. -- BThread线程结束了, AThread线程执行
[AThread] Thread end.
相信聪明的读者已经猜到为什么说
“主线程等待子线程的终止 ”的错误原因了吧,正确的说法应该是:“当前线程等待子线程的终止。”
五、从源码上看join()
方法
在AThread
的run()
方法里,执行了bt.join();
,进入看一下它的JDK源码:
public final void join() throws InterruptedException {
join(0);
}
然后再进入join(0)
方法:
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;
}
}
}
单纯从代码上来看,在
AThread
类中的run()
方法,bt.join()
是判断bt
的active
状态,如果bt
的isAlive()
方法返回false
,在b.join()
,这一点就不用等待BThread
线程结束,AThread
就可以继续向下进行。
isAlive()
方法的签名是public final native boolean isAlive();
,也就是说isAlive()
方法是判断当前线程的状态。