bigywater.tech
Java 内部原理 · 107

Thread.yield() 真实验证:调用它的线程真实完成次数只有对照组的0.2%

系列前面验证过 setPriority() 在真实调度里几乎没有效果,这篇换成 Thread.yield()——结果完全相反,效果大到夸张,同一台10核机器上,差距真实是500倍级别。

yield()线程真实吞吐量暴跌
真实测出:每次循环调用yield()的线程,300ms内真实只完成约165万次循环,不调用的对照组真实完成9亿+次
yield()真实完全不释放锁
真实验证:main线程持锁期间调用yield(),其他线程真实依然完全无法进入,证明yield()和锁释放毫无关系

上一篇:Arrays.binarySearch() 真实验证

真实验证:调用yield()的线程吞吐量真实暴跌到对照组的0.2%

两个线程做同样的空转计数,一个每次循环调用Thread.yield(),一个完全不调用,300毫秒后对比完成次数。

ThreadYieldDemo.java Thread yielding = new Thread(() -> { while (!stop.get()) { c++; Thread.yield(); } }); Thread normal = new Thread(() -> { while (!stop.get()) { c++; } });
真实实测(本机10核,三轮独立测试)
第1轮: 调用yield()的线程真实完成次数=1520664, 不调用yield()的线程真实完成次数=897428085, 比例=0.002
第2轮: 调用yield()的线程真实完成次数=1676430, 不调用yield()的线程真实完成次数=926965966, 比例=0.002
第3轮: 调用yield()的线程真实完成次数=1655559, 不调用yield()的线程真实完成次数=916975998, 比例=0.002
真实效果和线程优先级形成鲜明对比。系列前面 线程优先级那篇验证过,在同一台10核机器上,setPriority() 对线程吞吐量几乎没有可靠的真实影响。这次 Thread.yield() 给出了完全相反的真实结果:三轮独立测试,比例真实稳定在 0.002 左右——调用 yield() 的线程完成的工作量,真实只有不调用版本的约 0.2%。这说明尽管 JLS 规范同样把 yield() 描述为"给调度器的提示"、不做任何强制保证,但在真实的 HotSpot + macOS 调度环境下,每次循环调用一次 yield() 真实会让这个线程在绝大多数时候主动放弃当前时间片、排到调度队列末尾,对高频循环场景的吞吐量真实造成毁灭性影响——"不保证效果"不等于"没有真实效果",yield() 和 setPriority() 虽然都是"建议性"API,在真实平台上的实际影响力可以差出几个数量级。

真实验证:yield() 真实完全不释放任何锁

yield()调用期间,main线程手里持有的synchronized锁,是否会被真实释放出去?

ThreadYieldDemo.java synchronized (lock) { other.start(); // other线程试图抢同一把lock Thread.yield(); // main线程真实调用yield(),但依然在synchronized块内部 System.out.println(secondEntered.get()); }
真实实测
main线程持锁期间调用yield(),其他线程真实能否进入: false(应为false,yield()不释放锁)
main线程真实释放锁后,其他线程真实能否进入: true

真实结果证明了一个容易被误解的边界:yield() 影响的只是"当前线程是否继续占用CPU执行权",和"当前线程持有的锁"是两个完全独立的概念。main 线程在 synchronized 块内部调用 yield(),即使 CPU 执行权真的被让出去了,lock 这把锁依然真实被 main 线程持有,其他线程真实无法进入同步块——这和 wait()(会真实释放锁)是本质不同的两种机制,不能把 yield() 当作一种"临时让路"的同步手段来用。

分步演示:Thread.yield() 真实做了什么,又真实没做什么

每一行都是真实运行这段代码得到的结果。

Thread.yield() 真实不释放锁、真实不影响中断状态、真实不会抛异常——它真实只是一句"建议",连有没有被听进去都无法从返回值里判断
这一步新验证的yield()行为

    参考与说明

    • 本文全部结果均在本机(10核)真实运行 Java 17 得到,三轮独立测试的比例高度一致(均约0.002),锁不释放场景重复运行结果一致。
    • 和线程优先级那篇一起看,构成了系列对"调度建议类"API真实效果的完整两个案例对照——同样是"不保证",真实效果可以天差地别,不能一概而论。
    • 没有涉及:Thread.onSpinWait()(Java9+专门为自旋等待场景设计,语义比yield更精确)与yield()的真实差异、不同操作系统(Linux/Windows)上yield()真实效果是否同样显著——这两个话题留给系列后面按需再写。
    京ICP备2026067502号-1京公网安备11010502063487号