yield()是建议当前线程让出cpu,不保证效果;join()是阻塞当前线程直至目标线程结束,用于精确等待。两者均属线程协作方法,但yield()不改变线程状态且不释放锁,join()则导致阻塞并依赖目标线程终止。

Java 中 yield() 和 join() 都用于线程协作,但作用完全不同:前者是建议当前线程让出 CPU 时间片,后者是等待另一个线程执行完毕。它们不能直接“精确控制”执行顺序,但可在特定场景下辅助协调行为。
yield():提示调度器“我暂时不抢 CPU”
yield() 是 Thread 类的静态方法,它向线程调度器发出一个友好建议:当前线程愿意让出当前 CPU 使用权,让其他同优先级(或更高)的线程有机会运行。但它不保证任何实际效果——调度器可以忽略该请求,当前线程可能立刻又被选中继续执行。
- 适用于希望“主动礼让”的场景,比如自旋等待时减少忙等消耗
- 不会释放锁,也不会导致线程阻塞或状态变更(仍为 RUNNABLE)
- 对线程优先级敏感:低优先级线程调用 yield 基本无效;高优先级线程即使 yield,也可能立即被重新调度
- 示例:两个线程交替打印,配合 sleep 更可靠,单靠 yield 无法稳定实现
join():等待另一个线程彻底结束
join() 是实例方法,调用后当前线程会阻塞,直到目标线程执行完成(进入 TERMINATED 状态)。这是真正能影响执行顺序的机制,常用于“主线程等子任务完成后再继续”的典型场景。
- 底层基于
wait()实现,会释放锁(如果在同步块中调用),但不需要手动 notify - 支持超时版本:
join(long millis)或join(long millis, int nanos),避免无限等待 - 若目标线程已结束,join 立即返回;若被中断,抛出
InterruptedException - 常见用法:启动多个 worker 线程后,主线程调用它们的 join() 确保全部完成再汇总结果
别指望用 yield 实现确定性顺序
很多初学者误以为反复调用 yield() 就能让线程 A 执行完再轮到线程 B,这是不现实的。JVM 不保证调度策略,不同平台、不同 JDK 版本、甚至不同运行次数都可能导致行为差异。真正的顺序控制应依赖:
-
join()—— 适合“等待完成”类依赖 - 显式同步工具 —— 如
CountDownLatch、CyclicBarrier、Semaphore - 并发集合或原子变量 —— 协作共享状态
- 避免竞态 —— 用
synchronized或ReentrantLock保护临界区
join() 的典型安全用法
使用 join() 时要注意异常处理和资源释放:
- 始终在 try-catch 中调用,捕获
InterruptedException - 捕获后通常应恢复中断状态:
Thread.currentThread().interrupt(); - 避免在持有锁时调用 join(可能造成死锁风险),尤其在 synchronized 方法内
- 多个 join 可按需串行调用,也可用循环简化,如遍历线程列表逐一 join
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











