join不直接传递数据,需配合共享变量(volatile/atomic)、future或回调;future.get更推荐,因自动处理异常与超时;仅join无法保证可见性,须同步机制确保结果可读。

join 方法本身不直接传递数据,它只负责等待线程结束;要实现执行结果传递,必须配合共享变量、返回容器或回调机制。
用共享变量 + join 保证读取时机
主线程启动子线程后,不能立即读取子线程计算的值——因为可能还没算完。join 的作用就是“卡住主线程”,确保子线程执行完毕后再去读共享变量。
常见做法是定义一个线程安全的容器(如 AtomicInteger、AtomicReference 或普通字段加 final/volatile 修饰),让子线程写入结果,主线程在 join() 后读取:
- 子线程 run() 中完成计算 → 写入 result 字段
- 主线程调用 thread.join() → 确保子线程已退出
- 主线程再访问 result → 此时值一定已写入且可见(若字段为 volatile 或使用 Atomic 类)
用 Future + join 的替代思路(推荐)
虽然 join 是基础手段,但实际开发中更常用 Future 配合 ExecutorService 实现结果传递。它的本质仍是“等待+取值”,但封装更安全:
- submit(Callable
) 返回 Future - future.get() 内部会阻塞,直到任务完成并返回结果
- get() 的阻塞逻辑比手动 join + 共享变量更健壮(自动处理异常、中断、超时)
这比裸用 join + 手动同步更少出错,也更符合现代 Java 并发实践。
注意 join 无法解决的数据可见性问题
即使用了 join,如果共享变量没做正确同步,主线程仍可能读到旧值。这是因为:
- join 只保证执行顺序(B 完成后 A 才继续),不自动刷新主内存与工作内存
- 必须配合 volatile、Atomic 类、synchronized 或 final 字段,才能确保写入对主线程可见
例如:子线程给 int result = 42 赋值,主线程 join 后读 result,若 result 不是 volatile,JVM 可能优化为读寄存器缓存值,而非最新值。
不推荐:在 run() 中抛异常代替传结果
有人试图通过子线程抛出 RuntimeException 来“通知”主线程失败,但 join 不会把异常自动抛给调用方。异常只在子线程内终止其自身,主线程无感知。真正需要错误传递,应:
- 用 Future.get() —— 会包装成 ExecutionException 抛出
- 或用共享变量记录异常对象(如 AtomicReference
),join 后检查
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











