Java相关文章
- Java内存模型
- Java中String特性
- Java对象内存布局
- JVM结构
- JVM垃圾回收器
- Java19虚拟线程新特性
- Java线程生命周期与常见方法
- Java线程池笔记
- 浅谈synchronized锁原理
- 浅谈AQS原理
- ThreadLocal原理
- 浅谈双亲委派模型
- Java中的NIO
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。