深入理解Thread.sleep(0)的作用
作者:在下uptown
Thread.sleep
先回顾一下Thread.sleep(n)方法的用法,sleep只是去休眠n毫秒的时间,当前对象并没有释放掉锁,与Object.wait()方法最大的区别就在这,wait方法会释放掉锁,而sleep不会。
如此看来sleep(n)中的n是休眠n毫秒,那么n=0的时候理论上说毫无意义,但有时候阅读源码的时候又能看到这句。写中间件的大佬岂能犯这种错误。且听我细细道来
垃圾回收
还是要从垃圾回收说起,刚开始背垃圾回收八股文的时候根本都没想过JVM在什么时候回收辣鸡,直到练习时长两年班之后,在某个公众号推文上才知道,JVM有一个安全区域和安全点 safepoint的概念。
其实不难理解,程序跑着跑着代码里一个虚引用还没来及用呢,JVM突然回收直接给干没了,那肯定会出大问题。所以说要有一个合适的时机去做gc。
程序执行时并非在所有地方都能停顿下来开始GC,只有在特定的位置才能停顿下来开始GC,这些位置称为"安全点(Safepoint)"
如何在GC发生时,检查所有线程都跑到最近的安全点停顿下来呢?
- 抢先式中断:(目前没有虚拟机采用了) 首先中断所有线程。如果还有线程不在安全点,就恢复线程,让线程跑到安全点。
- 主动式中断: 设置一个中断标志,各个线程运行到SafePoint的时候主动轮询这个标志,如果中断标志为真,则将自己进行中断挂起。
安全区域是指一段代码片中,引用关系不会发生变化,在这个区域任何地方GC都是安全的,安全区域可以看做是安全点的一个扩展。线程执行到安全区域的代码时,首先标识自己进入了安全区域,这样GC时就不用管进入安全区域的线程了,线层要离开安全区域时就检查JVM是否完成了GC Roots枚举,如果完成就继续执行,如果没有完成就等待直到收到可以安全离开的信号
安全点完美的解决了如何进入GC问题,实际情况可能比这个更复杂,但是如果程序长时间不执行,比如线程调用的sleep方法,这时候程序无法响应JVM中断请求这时候线程无法到达安全点,显然JVM也不可能等待程序唤醒,这时候就需要安全区域了。
sleep(0)
理解了程序垃圾回收的时机再回过头来就不难理解sleep(0)的作用了,除了主动放弃调度之外,可以简单的理解为程序不是任意时刻都能gc,需要程序跑到safepoint点,而native方法执行以后就会插入一个safepoint,此时线程在执行JVM以外的代码不能对JVM的执行状态做修改,所以JVM进入safepoint可以忽略此线程。
也就是说sleep(0)的作用:
- 是主动让出cpu调度提升系统调度性能
- 是使系统进入safepoint标记gc。
使用场景:
Thread.sleep(0) 的使用场景非常有限,通常只在以下情况下考虑:
- 测试或调试: 在多线程测试或调试中,可以使用 Thread.sleep(0) 来强制触发线程切换,以便观察不同线程的执行顺序或行为。
- 某些底层优化: 在极少数情况下,某些底层代码可能会使用 Thread.sleep(0) 来尝试优化线程调度,例如,避免某个线程长时间占用 CPU 而导致其他线程饥饿。
- 实时系统(罕见): 在某些对实时性要求非常高的系统中,可能会使用 Thread.sleep(0) 来尝试更精细地控制线程调度。
代码示例:
public class ThreadSleepZeroExample { public static void main(String[] args) { Thread thread1 = new Thread(() -> { for (int i = 0; i < 5; i++) { System.out.println("Thread 1: " + i); if (i == 2) { Thread.sleep(0); // 触发线程调度 } } }); Thread thread2 = new Thread(() -> { for (int i = 0; i < 5; i++) { System.out.println("Thread 2: " + i); } }); thread1.start(); thread2.start(); } }
与 Thread.yield() 的区别:
实现方式:
Thread.yield() 是一个 Java API 调用,它的具体实现依赖于 JVM 和底层操作系统。
Thread.sleep(0) 在大多数操作系统上会被实现为一个非常短时间的睡眠(例如,1 毫秒或更短),或者直接触发一次线程上下文切换。
行为:
Thread.yield() 仅仅是给调度器一个提示,表示当前线程愿意让出 CPU。调度器可以忽略这个提示,继续让当前线程执行。
Thread.sleep(0) 由于涉及到了系统调用,它更可能导致实际的线程切换,因为它要求操作系统进行处理(即使时间很短)。虽然在实际上还是取决于操作系统的实现,不能百分百保证,但是会让步CPU的概率更大。
到此这篇关于深入理解Thread.sleep(0)的作用的文章就介绍到这了,更多相关Thread.sleep(0)作用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!