概念回顾:
sleep() 方法
sleep()
方法可以让线程进入“休眠”状态,暂停执行指定时间,时间到时再继续执行。在代码中使用 Thread.sleep()
方法可以使当前线程休眠一段时间,即暂停当前线程的执行,并释放CPU资源,让其他线程也有机会执行:
public static void sleep(long millis)
throws InterruptedException
方法参数 millis
表示要暂停多长时间,单位是毫秒。抛出 InterruptedException
异常,如果该线程在等待的过程中被中断了,则会抛出此异常。
该方法其实并不能保证实际的休眠时间就是我们指定的时间,受系统整体运行状态等多种因素可能会导致实际休眠时间偏长或偏短。
yield() 方法
yield()
方法是一个比较特殊的方法,它是在实现线程调度机制时使用的。它让当前线程暂停一下来让系统去执行其他的线程(包括自己的线程),但只是暂停了一下,具体是否让出 CPU 的运行权还需看系统的线程调度策略。
在代码中使用 Thread.yield()
方法可以使当前线程让出 CPU 执行时间片,让 CPU 调度器重新进行进程调度决策,从而可能让其他具备相同优先级的线程得到执行的机会:
二者区别:
1、 sleep()方法给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程以运行的机会;yield()方法只会给相同优先级或更高优先级的线程以运行的机会;
2、 线程执行 sleep()方法后转入阻塞(blocked)状态,而执行 yield()方法后转入就绪(ready)状态;
3、 sleep()方法声明抛出 InterruptedException,而 yield()方法没有声明任何异常;
4、 sleep()方法释放CPU执行时间片以便让其他线程获得执行机会,而yield()方法只是用来通知线程调度器该线程可以让出CPU时间,不保证其它线程一定能获取执行机会。
5、 sleep()方法比 yield()方法(跟操作系统 CPU 调度相关)具有更好的可移植性,通常不建议使用yield()方法来控制并发线程的执行
6、sleep()方法设置的时间一到,线程会自动被唤醒,而yield()方法并不能保证让出后的线程下一次就一定被执行
“不能保证让出后的线程下一次就一定被执行”的意思是,当一个线程调用了
Thread.yield()
方法后,只是向线程调度器发出一个通知,表示该线程愿意放弃当前正在使用的处理器资源,并不是真正让出处理器时间片和 CPU 资源给其他线程。尽管调用
yield()
方法会使线程从运行状态进入就绪状态,并且有可能让比它优先级更高的线程得到执行机会,但并不保证其它线程一定能获取执行机会,因为该线程未必真正释放了 CPU 资源,而 CPU 调度器也未必一定会把 CPU 时间片分配给其他线程。实际上,在现代操作系统中,线程的调度和运行都由操作系统内核进行管理。线程调度器会通过各种算法来决定哪个线程最先运行、运行多长时间以及何时切换线程等问题,而这些算法的具体设计取决于操作系统的实现。
总之,sleep() 方法主要是用来让线程休眠,等待指定的时间结束后再继续执行,而 yield() 方法则是让线程放弃当前的 CPU 资源,以便让其他线程运行,实现线程调度机制。
应用场景分析:
sleep() 方法的应用场景
-
定时任务。通过
Thread.sleep()
方法可以让线程暂停指定时间(例如1000毫秒),然后再执行后续任务。 -
控制循环速度。有时候需要让循环的执行速度变慢或更快,此时可以使用
Thread.sleep()
来控制每次循环的暂停时间。 -
模拟网络延迟。在开发网络应用程序的过程中,我们常常需要模拟网络传输时的延迟情况,通过调用
Thread.sleep()
方法来模拟数据包在网络传输中的延迟。
yield() 方法的应用场景
-
提高线程的并发度。当某个线程占用 CPU 时间过长时(例如在计算复杂的任务时),就会降低系统的并发度。通过在适当的时间点上调用
Thread.yield()
方法,能够使该线程让出 CPU 时间片,从而提高系统的并发度。 -
改善线程间的相对优先级。例如有两个线程的优先级相同,但一个线程必须完成某些重要的初始化工作,这时就可以在其它线程上调用
Thread.yield()
方法,使其它线程的代码早些运行,从而把执行控制让给初始化工作可能更为关键的线程。