Thread.yield()
方法是 Java 中的一个 静态方法,它的作用是 提示线程调度器当前线程愿意让出 CPU 使用权,使得其它具有相同优先级或更高优先级的线程能够执行。具体而言,它会将当前线程的状态从 运行态(Running) 转换为 就绪态(Ready),然后重新回到 就绪队列 中去,等待系统重新调度。
✅ 一、Thread.yield()
的作用
-
线程让步:当前线程调用
yield()
后,放弃当前的 CPU 时间片,并会进入 就绪队列。然后调度器会选择其他线程执行。 -
调度机会:
yield()
的调用会使得调度器重新安排当前线程和其他线程的执行顺序。 -
提高线程间公平性:在多个线程执行的情况下,调用
yield()
可以让相同优先级的线程有机会被执行,避免某个线程长期占用 CPU 资源。
✅ 二、yield()
的行为
-
在同一优先级线程中,
yield()
不会强制让当前线程立刻停止执行。它只是“请求”调度器将其从运行状态中移除,并且使得其它就绪线程(可能有相同的优先级或更高优先级)有机会获得 CPU 资源。 -
yield()
只是一个提示,具体的行为取决于操作系统的调度器,可能会:-
使线程进入就绪队列,等待重新调度。
-
不会发生任何变化,继续执行当前线程。
-
注意:
yield()
并不能保证线程立刻切换,实际行为是由操作系统的线程调度器控制的。
✅ 三、典型示例代码
public class ThreadYieldDemo {
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 10; i++) {
System.out.println("Thread 1 running");
Thread.yield(); // 提示让出 CPU
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 10; i++) {
System.out.println("Thread 2 running");
Thread.yield(); // 提示让出 CPU
}
});
thread1.start();
thread2.start();
}
}
在这个例子中,Thread.yield()
提示线程调度器,让两个线程有机会交替执行,避免一个线程长时间占用 CPU。
✅ 四、yield()
的限制
-
不保证线程切换:在某些操作系统中,
yield()
调用后可能不会发生线程切换,或者线程可能继续执行,特别是在没有其他线程需要执行时。 -
只适用于当前线程的优先级不高于其他线程的情况:如果当前线程的优先级比其他线程低,调用
yield()
后,它依然可能继续执行。
✅ 五、什么时候使用 yield()
?
-
提升线程之间的公平性:
yield()
可以让出 CPU 时间片,确保同优先级的线程都能有机会执行,避免某个线程长时间占用 CPU 资源。 -
减少线程的忙等待:如果某个线程在等待一些条件成立,可以通过
yield()
让出 CPU,避免不必要的资源占用。
✅ 六、与 sleep()
的区别
-
yield()
:仅仅是让出 CPU 时间片,不保证当前线程会被暂停或者其他线程立即运行。 -
sleep()
:让当前线程休眠指定的时间,确保当前线程会停止执行,直到时间到达。
特性 | yield() | sleep() |
---|---|---|
作用 | 提示线程调度器让出 CPU | 使当前线程休眠指定的时间 |
恢复时机 | 不保证立即切换,取决于调度器 | 当前线程休眠结束后继续执行 |
可调度性 | 依赖操作系统调度器的行为 | 线程强制停止,直到休眠时间到达 |
✅ 七、使用场景
yield()
用于:
-
线程间公平调度,避免某个线程占用过多的 CPU。
-
使 CPU 资源能够更加合理地分配给多个线程,避免饥饿问题。
但由于它的行为不可预测,通常在实际应用中并不常见。更常见的是使用 sleep()
来控制线程的执行时间,或者使用 线程池 来管理线程的生命周期和调度。
面试总结
Thread.yield()
是一个线程调度的提示方法,允许当前线程让出 CPU 使用权,并不保证立即停止,也不保证线程切换。它可以用来在多线程环境中实现线程间的公平性,但不能依赖于它来控制线程执行顺序。
是否需要我通过一个具体的示例来展示 yield()
的实际效果和行为?