一、join 方法概述
等待线程死亡:哪个线程调用 join 方法,那么其它线程会等待该线程执行完成,该方法等价于 join(0)(例如: t1.join() 即其它线程需要等待 t1 线程运行结束)
主要应用于线程同步,多个 join 是并行执行的
二、单个 join
为了探究 join 方法的作用,我们先看下列示例,并猜测结果
1、代码
@Slf4j
public class ThreadDemo {
private static int i = 1;
public static void main(String[] args) {
Runnable runnable = () -> {
log.info("t1 start...");
try {
Thread.sleep(3 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
i = 10;
log.info("t1 end...");
};
Thread t1 = new Thread(runnable, "t1");
t1.start();
log.info("main start...");
log.info("i 的值为: {}", i);
log.info("main end...");
}
}
2、运行结果
从上面的结果可以看出 i 的值为 1,而不是我们在 t1 线程内赋值的 10,如果我们想让 i 最终输出的值为 10,怎么办呢?
上面的代码理论上可以在 main 线程中也调用 Thread.sleep(time) 方法,只要 time 的值大于 3 * 1000,那么 i 的值就是 10 ,但是不推荐使用此方法,因为在实际的业务场景下,我们不能推断出 t1 线程的真正运行时间,time 的值就不好设定,如果 time 的值设定不合理,那么就有可能得到我们不想得到的结果.
那么还有其它的解决方式吗?
这个时候就需要使用 join() 方法了,只需要线程在调用 start() 方法之后调用 join() 方法即可
3、join 示例代码
@Slf4j
public class ThreadDemo {
private static int i = 1;
public static void main(String[] args) {
Runnable runnable = () -> {
log.info("t1 start...");
try {
Thread.sleep(3 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
i = 10;
log.info("t1 end...");
};
Thread t1 = new Thread(runnable, "t1");
t1.start();
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("main start...");
log.info("i 的值为: {}", i);
log.info("main end...");
}
}
运行结果
从上面的结果可以看出 i 的值为 10,符合我们的预期(main 线程一直在等待 t1 线程执行完毕之后才运行)
三、多个线程同时调用 join
1、代码
@Slf4j
public class ThreadDemo {
private static int i = 1;
private static int j = 1;
public static void main(String[] args) throws InterruptedException {
Runnable runnable1 = () -> {
log.info("t1 start...");
try {
Thread.sleep(3 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
i = 10;
log.info("t1 end...");
};
Runnable runnable2 = () -> {
log.info("t2 start...");
try {
Thread.sleep(4 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
j = 20;
log.info("t2 end...");
};
Thread t1 = new Thread(runnable1, "t1");
Thread t2 = new Thread(runnable2, "t2");
t1.start();
t2.start();
long start = System.currentTimeMillis();
t1.join();
t2.join();
long end = System.currentTimeMillis();
log.info("i: {} j: {} cost: {}", i, j, end - start);
}
}
2、运行结果
等待 t1 运行完毕需要 3s,等待 t2 运行完毕需要 4s, t1,t2 同时调用 join() 方法,最终消耗的时间是 4014 ms,可以看出 t1、t2 是并行执行的
3、如果将 t1.join() 和 t2.join() 调换位置,会得到什么结果呢?
可以看出,最终等待的时间还是 4014 ms,从而进一步印证了多个线程同时调用 join() 方法是并行执行的
四、join 的其它重载方法
等待该线程死亡的时间最长时间(单位为毫秒),超时为 0 意味着永远等待,如果在等待的时间内线程提前结束,那么等待时间就是线程结束的时间(例如 join(3*1000),而线程执行完成需要 2000 ms,那么等待的时间也是 2000 ms)