join 异步阻塞介绍
join 操作的原理是:
阻塞当前的线程,直到准备合并的目标线程的执行完成。
线程的 join 合并流程:
在 Java 中,线程(Thread)的合并流程是:假设线程 A 调用了线程 B 的 B.join 方法,合并 B线程。那么,线程 A 进入阻塞状态,直到 B 线程执行完成。
使用 join 实现异步泡茶喝的实践案例
流程图:
代码实现:
public class JoinDemo {
public static final int SLEEP_GAP = 500;
public static String getCurThreadName() {
return Thread.currentThread().getName();
}
static class HotWaterThread extends Thread {
public HotWaterThread() {
super("** 烧水—Thread");
}
@Override
public void run() {
try {
System.out.println("洗好水壶");
System.out.println("灌上凉水");
System.out.println("放在火上");
//睡一段时间 代表烧水
Thread.sleep(SLEEP_GAP);
System.out.println("水烧好了。");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("烧水 线程结束");
}
}
static class WashThread extends Thread {
public WashThread() {
super("$$ 清洗线程");
}
@Override
public void run() {
try {
System.out.println("洗茶杯");
System.out.println("洗水壶");
//睡一段时间 洗水壶
Thread.sleep(SLEEP_GAP);
System.out.println("洗完了。");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("清洗 线程结束");
}
}
public static void main(String[] args) {
HotWaterThread hotWaterThread = new HotWaterThread();
WashThread washThread = new WashThread();
hotWaterThread.start();
washThread.start();
try {
//合并烧水线程
hotWaterThread.join();
//合并清洗线程
washThread.join();
Thread.currentThread().setName("主线程");
System.out.println("泡喝茶~~~");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("真好喝 拜拜~ 运行结束!");
}
}
程序中有三个线程:(1)主线程 main;(2)烧水线程 hThread;(3)清洗线程 wThread。
main 主线程调用了 hThread.join()实例方法,合并烧水线程,也调用了 wThread.join()实例方法,合并清洗线程。
join 合并方法:
join 方法的应用场景:A 线程调用 B 线程的 join 方法,等待 B 线程执行完成;在 B 线程没有完成前,A 线程阻塞。
join 方法是有三个重载版本:
(1)void join():A 线程等待 B 线程执行结束后,A 线程重新恢复执行。
(2)void join(long millis):A 线程等待 B 线程执行一段时间,最长等待时间为 millis 毫秒。 超过 millis 毫秒后,不论 B 线程是否结束,A 线程重新恢复执行。
(3)void join(long millis,int nanos):等待 B 线程执行一段时间,最长等待时间为 millis 毫秒, 加 nanos 纳秒。超过时间后,不论 B 线程是否结束,A 线程重新恢复执行。
注意以下容易混淆的几点:
(1)join 是实例方法,不是静态方法,需要使用线程对象去调用,如 thread.join()。
(2)join 调用时,不是线程所指向的目标线程阻塞,而是当前线程阻塞。
(3)只有等到当前线程所指向的线程执行完成,或者超时,当前线程才能重新恢复执行。
join 有一个问题:被合并的线程没有返回值。例如,在烧水的实例中,如果烧水线程的执行结束,main 线程是无法知道结果的。同样,清洗线程的执行结果,main 线程也是无法知道的。形象地说,join 线程合并就是一像一个闷葫芦。只能发起合并线程,不能取到执行结果。
如果需要获得异步线程的执行结果,怎么办呢?可以使用 Java 的 FutureTask 系列类。