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

深入理解 Java join:它到底做了什么?和协程挂起有什么区别?

很多人第一次接触join()时都会产生疑问:

  1. 它是不是加入线程队列?
  2. 它是不是让线程顺序执行?
  3. 它是不是像 Kotlin 的挂起?

如果你也有这些疑惑,这篇文章会从 0 带你彻底讲透。

一、join 是什么?

一句话定义:

join()的作用是:让当前线程等待另一个线程执行结束。

它不是排队机制,不是调度策略,也不是线程池概念。

它只是一个“等待”。

二、最基础示例

public class JoinDemo { public static void main(String[] args) throws InterruptedException { Thread t = new Thread(() -> { try { Thread.sleep(2000); } catch (Exception ignored) {} System.out.println("子线程结束"); }); t.start(); t.join(); // 等待 t 执行完 System.out.println("主线程继续执行"); } }

输出顺序一定是:

(2秒后) 子线程结束 主线程继续执行

因为:

  • main 线程在join()处阻塞
  • 必须等子线程结束
  • 才会继续执行

三、没有 join 会发生什么?

t.start(); System.out.println("主线程继续执行");

可能输出:

主线程继续执行 子线程结束

因为:

  • main 不会等子线程
  • 两个线程是并发执行

四、join 的本质:阻塞线程

从本质上讲:

join 会让当前线程进入 WAITING 状态

它底层逻辑类似:

while (thread.isAlive()) { wait(); }

当目标线程结束时,会唤醒等待线程。

所以:

join = 阻塞当前线程

五、join 不是队列机制

很多人误以为 join 是“加入执行队列”。

实际上:

概念是不是队列
Thread.join❌ 不是
线程池任务队列✅ 是
MQ✅ 是

join 不会改变执行顺序,它只是等待。

六、join 和 sleep 的区别

对比joinsleep
等谁等另一个线程等固定时间
是否阻塞线程
是否依赖目标线程

join 是“等别人结束”。

sleep 是“自己睡一会”。

七、join(long millis)

t.join(1000);

含义:

最多等 1 秒

如果 1 秒后线程还没结束,主线程会继续执行。

这是带超时的等待机制。

八、多个 join

t1.start(); t2.start(); t1.join(); t2.join();

含义:

依次等待 t1、t2 执行结束。

这常用于:

  • 多线程任务合并
  • 等待多个子线程完成

九、为什么现代工程中很少用 join?

因为:

  • join 会阻塞线程
  • 阻塞 = 占用线程资源
  • 高并发系统要减少阻塞

在后端开发中更常见的是:

  • Future.get()
  • CompletableFuture
  • CountDownLatch
  • 协程 await

但注意:

它们的思想本质一样 —— 等待任务完成。

十、join 和 Kotlin 协程的区别

很多人会问:

join 像不像 Kotlin 的 delay?

答案是:

❌ 不一样

对比Java joinKotlin delay
是否阻塞线程
暂停的是谁线程协程
资源是否被占用占用

不占用

核心区别:

阻塞 = 线程不能干别的 挂起 = 协程不能干别的

join 属于线程阻塞模型。

delay 属于协程挂起模型。

十一、工程视角理解

假设 10000 个请求都需要等待 2 秒。

如果用 join/sleep:

  • 10000 个线程
  • 内存暴涨
  • 上下文切换频繁

如果用协程 delay:

  • 几十个线程
  • 10000 个挂起协程
  • 高效复用线程

这就是线程模型和协程模型的差异。

十二、最终总结

压缩成三句话:

join = 等待另一个线程结束 join = 阻塞当前线程 join ≠ 队列机制

再压缩成一句工程脑口诀:

阻塞的是线程,不是任务。

结语

理解 join 的关键,不在于 API 本身。

而在于理解:

  • 什么是线程阻塞
  • 什么是线程资源
  • 什么是并发模型

当你能区分:

  • 线程层
  • 协程层
  • 任务层

你的并发认知就进入了高级阶段。

http://www.jsqmd.com/news/403281/

相关文章:

  • Java 版 Claude Code CLI 来了!(国产开源)Solon Code CLI 发布
  • [AI提效-15]-豆包多对话功能详解:打破传统AI工具“单对话单一主题、新对话从零起步”的局限,高效衔接创作,告别反复沟通成本。
  • SpringBoot整合ES8向量检索:构建高精度智能客服系统的工程实践
  • 幽灵客户端
  • 电商智能客服Agent工作流架构优化实战:从高延迟到毫秒级响应
  • 视频孪生平台之上:镜像视界三维实时解算体系在港口与机场复杂场景协同治理中的全球领先性研究
  • 视频孪生平台之上:镜像视界三维实时解算体系在公安空间治安操作系统中的全球领先性研究
  • 大规模语言模型的反事实推理在战略规划中的多维度应用
  • 解读AI原生应用领域差分隐私的重要性
  • C++罗马曲面3D旋转程序代码解说_C++精灵库应用案例
  • 【开题答辩全过程】以 高校实验室管理系统为例,包含答辩的问题和答案
  • AI应用架构师困惑:AI驱动芯片设计,数据不够怎么办?
  • [use agent-browser not playwright directly]
  • AI-RAN Sionna开发者套件全解析:从入门到集群,开启无线通信与AI融合开发新纪元
  • AI原生应用领域自主代理的故障诊断与修复
  • Vue实现智能客服对话框与推荐问题展示:从架构设计到AI集成实战
  • 如何在WSL中设置AMD AI MAX 395的Rocm微调环境
  • Flink实时计算心智模型——流、窗口、水位线、状态与Checkpoint的协作
  • 百度AI智能客服Prompt设置实战:从零搭建高效对话系统的避坑指南
  • 2024提示工程安全趋势:加密传输机制的3个创新方向
  • 【GitHub项目推荐--Heretic:全自动语言模型去审查工具】⭐⭐⭐
  • 【GitHub项目推荐--Flet:Python全栈开发者的跨平台应用框架】⭐
  • 智能客服转人工:从架构设计到实战避坑指南
  • Node.js运维部署实战:从0到1开始搭建Node.js运行环境
  • 修复网页失效的css
  • 倒立摆系统MPC控制MATLAB代码功能说明
  • 近况报告(II)
  • 北京大兴区附近回收黄金店实测,在跑了三家之后,我更看重这三点
  • 基于MCP的智能客服系统搭建:从架构设计到性能优化实战
  • 客服在线会话智能体流程图:从零构建高可用对话系统的实践指南