#使用场景
有时候我们在主线程中生成了子线程,如果子线程中有进行大量的耗时操作,主线程会比子线程早结束,这也是没有问题的,但是如果主程序在结束之前需要子线程的处理结果,那么就必须要等子线程结束之后才能结束主线程。这个时候我们就可以用join()方法。
多线程按照自己指定的顺序执行。
例子
线程1:
class OneThread extends Thread {
public OneThread() {
super("[OneThread] Thread");
}
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println(name + " start.");
try {
for (int i = 0; i < 5; i++) {
System.out.println(name + " loop at " + i);
Thread.sleep(1000);
}
System.out.println(name + " end.");
} catch (Exception e) {
System.out.println("Exception from " + name + ".run");
}
}
}
class TwoThread extends Thread {
BThread bt;
public TwoThread(BThread bt) {
super("[Twohread] Thread");
this.bt = bt;
}
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println(name + " start.");
try {
bt.join();
System.out.println(name + " end.");
} catch (Exception e) {
System.out.println("Exception from " + name + ".run");
}
}
}
public class TestDemo {
public static void main(String[] args) {
String name = Thread.currentThread().getName();
System.out.println(name + " start.");
OneThread one = new OneThread();
TwoThread two = new TwoThread(one);
try {
one.start();
Thread.sleep(2000);
two.start();
two.join();
} catch (Exception e) {
System.out.println("Exception from main");
}
System.out.println(name + " end!");
}
}
执行结果:
main start. //主线程起动,因为调用了two.join(),要等到two结束了,此线程才能向下执行。
[OneThread] Thread start.
[OneThread] Thread loop at 0
[OneThread] Thread loop at 1
[TwoThread] Thread start. //线程two启动,因为调用one.join(),等到one结束了才向下执行。
[OneThread] Thread loop at 2
[OneThread] Thread loop at 3
[OneThread] Thread loop at 4
[OneThread] Thread end.
[TwoThread] Thread end. // 线程TwoThread在one.join();阻塞处起动,向下继续执行的结果
main end! //线程TwoThread结束,此线程在two.join();阻塞处起动,向下继续执行的结果.
如果我们去掉: two.join();
public class TestDemo {
public static void main(String[] args) {
String name = Thread.currentThread().getName();
System.out.println(name + " start.");
OneThread one = new OneThread();
TwoThread two = new TwoThread(one);
try {
one.start();
Thread.sleep(2000);
two.start();
// two.join();
} catch (Exception e) {
System.out.println("Exception from main");
}
System.out.println(name + " end!");
}
}
打印结果:
main start. // 主线程起动,因为Thread.sleep(2000),主线程没有马上结束;
[OneThread] Thread start. //线程BThread起动
[OneThread] Thread loop at 0
[OneThread] Thread loop at 1
main end! // 在sleep两秒后主线程结束,TwoThread执行的one.join();并不会影响到主线程。
[TwoThread] Thread start. //线程two起动,因为调用了one.join(),等到one结束了,此线程才向下执行。
[OneThread] Thread loop at 2
[OneThread] Thread loop at 3
[OneThread] Thread loop at 4
[OneThread] Thread end. //线程OneThread结束了
[TwoThread] Thread end. // 线程TwoThread在OneThread.join();阻塞处起动,向下继续执行的结果
源码分析
在TwoThread的run方法里,执行了one.join();
,进入看一下它的JDK源码:
public final void join() throws InterruptedException {
join(0);
}
然后进入join(long millis)
方法:
public final void join(long millis) throws InterruptedException {
synchronized(lock) {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
lock.wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
lock.wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
}
private volatile long nativePeer;
/**
* Tests if this thread is alive. A thread is alive if it has
* been started and has not yet died.
*
* @return <code>true</code> if this thread is alive;
* <code>false</code> otherwise.
*/
public final boolean isAlive() {
return nativePeer != 0;
}
@FastNative
public final native void wait(long millis, int nanos) throws InterruptedException;
注意点:
- 如果线程被生成了,但还未被起动,
isAlive()
将返回false
,调用它的join()方法是没有作用的。将直接继续向下执行。 - 在
TwoThread
类中的run
方法中,one.join()
是判断one``的active
状态,如果one的isActive()
方法返回false
,在one.join(),这一点就不用阻塞了,可以继续向下进行了。从源码里看,
wait方法中有参数,也就是不用唤醒谁,只是不再执行
wait`,向下继续执行而已。 - 在
join()
方法中,isAlive()
方法的签名是:public final native boolean isAlive()
,也就是说isAlive()
是判断当前线程的状态,也就是one
的状态。