当前位置: 首页 > web >正文

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)。直到 workerThreadrun() 方法全部执行完毕,主线程才会被唤醒,从 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
主线程结束。
...

总结(初学者要点)

  1. join()Thread的方法。
  2. a.join() 的意思是,当前线程暂停,等待 a 线程执行完毕。
  3. 它最常见的用途是:一个线程需要依赖另一个线程的执行结果或状态
  4. join() 会让当前线程进入阻塞状态。
  5. 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() + "主线程结束。");}
}
http://www.xdnf.cn/news/14210.html

相关文章:

  • python+django/flask+uniapp宠物中心信息管理系统app
  • Java开发中避免NullPointerException的全面指南
  • 【三维重建】无位姿图像的大场景On-the-fly重建
  • 【Linux】初见,进程概念
  • 创客匠人解析:美团护城河战略对 IP 可持续变现的启示
  • TCP 协议
  • 2025年EAAI SCI1区TOP,贪婪策略粒子群算法GS-IPSO+无人机桥梁巡检覆盖路径规划,深度解析+性能实测
  • 函数式编程 stream流 lambda表达式
  • event.target 详解:理解事件目标对象
  • 学习昇腾开发的第二天--PC机远程登录开发板
  • 大IPD之——华为的管理变革与战略转型之道(三)
  • 05-Linux软件安装与前后端项目部署
  • adoc(asciidoc)转为markdown的方法,把.adoc文件转换为markdown格式
  • PostgreSQL的扩展pg_visibility
  • 【办公类-25-05】20250514 Python模拟UIBOT上传园园通截图(自动最小化界面,时间部分的删除和黏贴)
  • 【CSS-13】CSS 网页布局三大机制详解:普通流、浮动与定位
  • 2.2 订阅话题
  • aflplusplus:开源的模糊测试工具!全参数详细教程!Kali Linux教程!(三)
  • 开源统一数据库管理平台完全指南:私有化部署方案与技术解析
  • 解决Spark4.0.0依赖问题
  • http的缓存问题
  • pytorch 实战二 CNN手写数字识别
  • Spring MVC 中日期格式转换的两种实用方法
  • Hive 性能优化:从表设计到查询执行的全链路优化
  • rust的main.rs和lib.rs该怎么写
  • 【项目实训#07】HarmonyOS API知识图谱构建与系统知识图谱后端实现
  • 【Qt】QStateMachine状态机-对状态机分组、历史状态,实现复杂状态机
  • 玩转Docker | 使用Docker部署Blinko个人笔记工具
  • 如何在FastAPI中构建一个既安全又灵活的多层级权限系统?
  • 刚学到一个使用共享软件而禁用弹窗的工具:微软电脑管家