Thread的join方法
文章目录
- 1. `join()` 是什么意思?一句话理解
- 2. 没有 `join()` 会发生什么?(代码示例)
- 3. 使用 `join()` 解决问题(代码示例)
- 4. 带超时的 `join(long millis)`
- 总结(初学者要点)
好的,完全没问题!
join()
方法是多线程编程中一个非常基础且重要的概念,我们用最简单的方式来理解它。
1. join()
是什么意思?一句话理解
join()
的字面意思是“加入”或“汇合”。在多线程里,你可以把它想象成插队。
当你在一个线程A中调用另一个线程B的 join()
方法时(B.join()
),意思就是:
“线程A,你给我停下,暂停执行。必须等线程B执行完所有任务,彻底结束之后,你才能继续往下走。”
简单说,就是线程B要“插队”到线程A前面,线程A必须等线程B办完事。
2. 没有 join()
会发生什么?(代码示例)
我们来看一个场景:主线程(main)启动了一个工作线程(worker),主线程需要拿到工作线程计算的结果才能打印最终报告。
如果不用 join()
,主线程和工作线程是各跑各的,主线程不会等工作线程。
代码清单1:各跑各的(错误示范)
public class JoinExample_Problem {static int result = 0; // 用于存放计算结果的共享变量public static void main(String[] args) throws InterruptedException {System.out.println("主线程开始...");// 创建并启动一个工作线程,它需要2秒钟来计算Thread workerThread = new Thread(() -> {System.out.println("工作线程开始计算...");try {Thread.sleep(2000); // 模拟耗时的计算result = 100; // 计算结果为100System.out.println("工作线程计算完成。");} catch (InterruptedException e) {e.printStackTrace();}});workerThread.start();// !!!注意这里:主线程没有等待,直接往下走了// 由于主线程不会等工作线程,它几乎立刻就执行到这里// 此时工作线程还在睡着,result 还是 0System.out.println("主线程打印最终结果: " + result); System.out.println("主线程结束。");}
}
运行结果:
主线程开始...
工作线程开始计算...
主线程打印最终结果: 0 <-- 看!结果是错误的!
主线程结束。
工作线程计算完成。
问题分析:主线程启动了工作线程后,根本不理会它是否完成,直接就去打印 result
,而此时 result
还是初始值0,所以得到了错误的结果。
3. 使用 join()
解决问题(代码示例)
现在,我们只加一行代码 workerThread.join();
,让主线程“插队”等待。
代码清单2:使用join()等待(正确示范)
public class JoinExample_Solution {static int result = 0;public static void main(String[] args) throws InterruptedException {System.out.println("主线程开始...");Thread workerThread = new Thread(() -> {System.out.println("工作线程开始计算...");try {Thread.sleep(2000);result = 100;System.out.println("工作线程计算完成。");} catch (InterruptedException e) {e.printStackTrace();}});workerThread.start();// --- 关键在这里 ---// 主线程调用 workerThread.join(),主线程会在这里暂停// 直到 workerThread 的 run() 方法执行完毕System.out.println("主线程正在等待工作线程完成...");workerThread.join(); System.out.println("主线程确认工作线程已完成。");// --- 等待结束 ---// 现在,主线程可以安全地使用工作线程的计算结果了System.out.println("主线程打印最终结果: " + result);System.out.println("主线程结束。");}
}
运行结果:
主线程开始...
工作线程开始计算...
主线程正在等待工作线程完成...
(等待约2秒)
工作线程计算完成。
主线程确认工作线程已完成。
主线程打印最终结果: 100 <-- 看!结果正确了!
主线程结束。
效果分析:主线程执行到 workerThread.join()
时,就进入了阻塞等待状态,CPU会去执行其他线程(比如 workerThread
)。直到 workerThread
的 run()
方法全部执行完毕,主线程才会被唤醒,从 join()
的下一行代码继续执行,此时 result
已经是正确的100了。
4. 带超时的 join(long millis)
join()
还有一个带参数的版本,比如 join(1000)
。
意思是:“我最多只等你1秒钟,如果你1秒钟还没搞完,那我就不等了,我自己往下走了。”
这在防止无限期等待时非常有用。
代码清单3:带超时的join()
// ... 和上面代码类似 ...
public static void main(String[] args) throws InterruptedException {// ... 启动工作线程的代码 ...workerThread.start();System.out.println("主线程最多等待1秒钟...");// 工作线程需要2秒,但主线程最多只等1秒workerThread.join(1000); System.out.println("主线程不等了,继续往下走。");System.out.println("主线程打印最终结果: " + result); // 此时结果还是0System.out.println("主线程结束。");
}
运行结果:
...
主线程最多等待1秒钟...
(等待1秒后)
主线程不等了,继续往下走。
主线程打印最终结果: 0
主线程结束。
...
总结(初学者要点)
join()
是Thread
类的方法。a.join()
的意思是,当前线程暂停,等待a
线程执行完毕。- 它最常见的用途是:一个线程需要依赖另一个线程的执行结果或状态。
join()
会让当前线程进入阻塞状态。join(long)
是一个有“耐心限度”的版本,可以避免死等。
package join;public class Main {static int result = 0;public static void main(String[] args) throws InterruptedException {System.out.println(Thread.currentThread().getName() + "主线程开始...");Thread workerThread = new Thread(() -> {System.out.println("工作线程开始计算...");try {Thread.sleep(2000);result = 100;System.out.println("工作线程计算完成。");} catch (InterruptedException e) {e.printStackTrace();}});workerThread.start();// --- 关键在这里 ---// 主线程调用 workerThread.join(),主线程会在这里暂停// 直到 workerThread 的 run() 方法执行完毕System.out.println(Thread.currentThread().getName() + "主线程正在等待工作线程完成...");workerThread.join();System.out.println(Thread.currentThread().getName() + "主线程确认工作线程已完成。");// --- 等待结束 ---// 现在,主线程可以安全地使用工作线程的计算结果了System.out.println(Thread.currentThread().getName() + "主线程打印最终结果: " + result);System.out.println(Thread.currentThread().getName() + "主线程结束。");}
}