1. 概述
在本篇文章中,我们将深入探讨 Thread
类中的 yield()
方法。
我们会将它与 Java 中其他并发机制进行对比,并最终分析它的实际应用场景。
2. yield() 方法简析
正如官方文档所述,yield()
提供了一种机制,用于告知线程调度器:“当前线程愿意让出处理器的使用权,但希望尽快被重新调度执行。”
⚠️ 调度器可以选择性地采纳或忽略这个提示,而且其行为在不同操作系统上可能有所不同。
下面这段代码展示了两个相同优先级的线程在每次调度后调用 yield()
的情况:
public class ThreadYield {
public static void main(String[] args) {
Runnable r = () -> {
int counter = 0;
while (counter < 2) {
System.out.println(Thread.currentThread()
.getName());
counter++;
Thread.yield();
}
};
new Thread(r).start();
new Thread(r).start();
}
}
当我们多次运行上述程序时,会得到不同的输出结果。例如:
运行 1:
Thread-0
Thread-1
Thread-1
Thread-0
运行 2:
Thread-0
Thread-0
Thread-1
Thread-1
✅ 可见 yield()
的行为是非确定性的,且依赖于平台。
3. 与其他并发机制的比较
Java 中还有其他一些控制线程执行顺序的机制,包括来自 Object
类的 wait()
、notify()
和 notifyAll()
,以及来自 Thread
类的 join()
和 sleep()
。
下面我们看看它们与 yield()
之间的区别。
3.1. yield() vs wait()
yield()
是在线程上下文中直接调用的;而wait()
必须在同步块或方法中、显式获取锁之后才能调用。- 与
yield()
不同,wait()
可以指定一个最小等待时间,在此之前不会尝试重新调度该线程。 - 使用
wait()
后,可以通过对相关对象调用notify()
或notifyAll()
来随时唤醒线程。
3.2. yield() vs sleep()
yield()
只是启发式地尝试暂停当前线程的执行,不保证何时会被重新调度;- 而
sleep()
则可以强制调度器暂停当前线程至少参数指定的时间。
3.3. yield() vs join()
- 当前线程可以在任意其他线程上调用
join()
,表示当前线程需要等待该线程执行完毕后再继续执行。 join()
还可以接受一个时间参数,表示当前线程最多等待多久后就恢复执行。
4. yield() 的使用场景
根据官方文档建议,通常情况下我们很少需要使用 yield()
,因此除非你非常清楚其行为并有明确目的,否则应尽量避免使用。
尽管如此,yield()
在某些特定场景下仍有价值,例如:
- 设计自定义的并发控制结构
- 在计算密集型任务中提升系统响应性
⚠️ 但这些用法都必须配合详细的性能测试和基准验证,以确保能达到预期效果。
5. 总结
本文简要介绍了 Thread
类中的 yield()
方法,并通过代码示例展示了它的行为特点和局限性。
同时我们也对比了它与其他 Java 并发机制的区别,并列举了一些可能适用的场景。
一如既往,本文所有示例代码均可在 GitHub 上找到。