在很多情况下,主线程创建并启动子线程,如果子线程中要进行大量的耗时计算,主线程会比子线程提前结束,如果主线程需要用到子线程返回的结果,就要用到join()方法了,这样就将异步的变为同步的了。
比如下面这个例子,如果不用join(),我们将无法控制运行流程
子线程随机休眠时间
public class ThreadA extends Thread{
public void run() {
try {
int waitTime = (int) (Math.random()*1000);
Thread.sleep(waitTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("子线程运行完了");
}
}
public static void main(String[] args) throws InterruptedException {
ThreadA thread = new ThreadA();
thread.start();
//Thread.sleep(2000); 这里我们并不知道应该设定多少时间才能当子线程运行完成后再运行主线程
System.out.println("我想当子线程运行结束后再出现");
}
使用join()方法
public static void main(String[] args) throws InterruptedException {
ThreadA thread = new ThreadA();
thread.start();
//Thread.sleep(2000);
thread.join(); //加上子线程的join()方法后
System.out.println("我想当子线程运行结束后再出现");
}
主线程会等待子线程运行完后再运行
join(long)方法中的参数表示,超过设定时间后就继续运行主线程,不再等待子线程了,这一点和sleep(long)很相似,但是两者是有区别的,join(long)内部是用wait(long)实现的,会释放锁,sleep(long)不释放锁;
join的源码:
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); //这里是用了wait(long),会释放锁
now = System.currentTimeMillis() - base;
}
}
}
我们还可以通过join控制多个线程的执行顺序
思路:例如有三个线程a b c,我们可以在c线程中启动b线程,在b线程中启动a线程,这样,我们最先在主线程中启动c线程后,c会等待b线程执行完,b线程又会等待a线程执行完,这样产生的结果是a线程第一个执行完,b次之,c最后
public class ThreadC extends Thread {
private ThreadB b; //在c线程中启动b,需要持有b线程的对象
public ThreadC(ThreadB b) {
this.b = b;
}
public void run() {
try {
b.start();
b.join(); //b线程与c线程合并,c会等待b执行完
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程C执行了");
}
}
public class ThreadB extends Thread {
private ThreadA a; //在b线程中启动a,需要持有a线程的对象
public ThreadB(ThreadA a) {
this.a = a;
}
public void run() {
try {
a.start();
a.join(); //a线程与b线程合并,b会等待a执行完
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程B执行了");
}
}
public class ThreadA extends Thread{
public void run() {
System.out.println("线程A执行了");
}
}
public static void main(String[] args) {
ThreadA a = new ThreadA();
ThreadB b = new ThreadB(a);
ThreadC c = new ThreadC(b);
c.start();
}
运行结果
线程A执行了
线程B执行了
线程C执行了