Java语言中wait、sleep和yield是三个方法相同点和不同点

wait、sleep和yield三个方法相同点和不同点

如各位希望转载或引用,请注明出处,尊重原创,谢谢。如有疑问或错误,欢迎邮件沟通。
​
gitHub地址:https://github.com/thinkingfioa
邮箱地址:[email protected]
博客地址: https://blog.csdn.net/thinking_fioa
项目地址:https://github.com/thinkingfioa/tech-summary

1. 背景

介绍Java语言中有三个与线程非常重要的方法:wait()和sleep()和yield()。三个方法各有各的特殊性,分别在不同的场景下使用。

本文将从锁机制、CPU和高精度时间控制方面揭示出三个方法的不同点。

2. 分析

2.1 wait()方法

wait()方法是Object类的方法,调用对象的wait()方法后,当前线程主动放弃CPU,进入等待状态,并释放掉当前线程获得的所有锁(如果有的话)。线程进入阻塞状态后,只有其他线程调用同一对象的notify()方法(或notifyAll()方法)时才能唤醒等待池中的该线程进入等锁池,如果线程重新获得锁(如果有的话)就可以进入就绪(READY)状态,等待操作系统调度后重新执行。

等待过程中,操作系统会将CPU分配给其他的线程使用。

注意:请区别与await()方法,与await()方法配套使用的方法是signal()或signalAll()方法,通常配合Condition+ReentrantLock使用的。wait()方法更多和synchronized关键字配套使用。

2.2 sleep()方法

sleep()方法是Thread类的静态方法,它的作用是在指定的毫秒数内让当前“正在执行的线程”暂停执行“(休眠)。如果调用了sleep方法,必须捕获InterruptedException异常或者将该异常向上层抛出。

当线程睡眠时间满后,不一定会立即得到执行,因为此时可能CPU正在执行其他的任务,所以说调用sleep()方法相当于让线程进入阻塞状态。

以下几点使用Thread.sleep(XXX)方法时,需特殊注意

2.2.1 sleep()方法不会释放锁

某个线程调用sleep()方法后,如果当前线程持有某个对象的锁,将会继续持有,该点与wait()方法和await()方法不同。

线程调用完sleep()方法后,即使操作系统中CPU处于空闲状态,处于sleep()的线程也不会执行。

2.2.2 sleep()究竟是让哪一个线程休眠

main方法中调用某一个线程类的对象t1.sleep(),睡眠的不是t1,而是调用sleep()方法时所在类的main线程。在Runner1的run()中不写sleep(),在主线程中写Runner1.sleep(5000)时,结果不是Runner1睡眠,还是主线程睡眠。总体的原则就是:谁调用,谁等待,和具体的对象无关

2.2.3 sleep()方法精度问题

很多程序希望实现高精度时间控制机制,比如每1ms发送10笔请求,开发人员可能希望通过sleep(1)方法来实现。

sleep(long millis)方法受到操作系统计时器、调度程序精度和准确性的影响,无法实现高进度的时间控制。我们发现,部分windows操作系统甚至无法区分出15ms以下时间误差。所以,如果程序想控制20ms以下的时间精度,建议不要使用sleep()方法。推荐使用方法在我的另一篇博客中介绍。

2.3 yield()方法

yield()方法是Thread类的静态方法,它是一个线程让步方法。所谓让步,其实是当一个线程调用了这个方法之后,它就会主动让出CPU资源,转入就绪(READY)状态,系统的线程调度器将会重新调度一次,但实际中可能无法保证yield()达到让步目的,因为让步的线程可能会被再次选中执行,当然也可能被其他高优先级的线程抢到CPU。

注意:yield()方法不会阻塞该线程,它只是将线程转入就绪状态,等待再次被调度。

2.3.1 yield()方法不会释放锁

与sleep()方法一样,不会释放当前线程拥有的锁。

2.3.2 yield()方法精度问题

可以基于yield()方法实现较高精度的时间控制机制。通常,我们会采用sleep()和yield()两个组合方式,实现线程等待固定时间的需求,可参考本人的另一篇博客详细讲解该点。

3. 总结

  1. 调用wait()/await()方法后,线程会主动释放自己获得的所有锁;而sleep()和yield()方法不会。

  2. 调用wait()方法和sleep()方法后,线程会主动进入阻塞状态,其他线程(无论是高低优先级)都有可能获得CPU资源;而调用yield()方法后,当前线程、相同优先级或更高优先级的线程获得CPU资源;

  3. 线程执行wait()方法和sleep()方法后转入WAITING状态,而执行yield()方法后转入就绪(READY)状态;

  4. sleep()方法比yield()方法(跟操作系统CPU调度相关)具有更好的可移植性。

参考资料

你可能感兴趣的:(java,java,多线程,thread,wait,sleep)