Thread.sleep(0)的写法原理深入解析

 更新时间:2022年12月27日 14:04:05   作者:JAVA旭阳  
这篇文章主要为大家介绍了Thread.sleep(0)的写法原理深入解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

前言

最近在网上看到了一段代码,让我感到很迷茫。他在代码中使用了 Thread.sleep(0),让线程休眠时间为0秒,具体代码如下。

int i = 0;
while (i<10000000) {
    // business logic
    //prevent long time gc
    if (i % 3000 == 0) {
        try {
            Thread.sleep(0);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

sleep了0秒,不就是不睡觉吗?我的第一反应是这段代码没什么用,但是看到他的注释又引起了我的兴趣。经过一番研究,看似无用的一段代码,其实大有文章。

探索分析

为了找到原因,首先去看下sleep方法的javadoc,如下:

Causes the currently executing thread to sleep (temporarily ceaseexecution) for the specified number of milliseconds, subject tothe precision and accuracy of system timers and schedulers. The thread does not lose ownership of any monitors.

显然没有得到正确的答案,最后在询问作者说是使用Thread.sleep(0)可以暂时释放CPU时间线。

时间片循环调度算法

在操作系统中,CPU有很多竞争策略。Unix系统采用时间片循环调度算法。在该算法中,所有进程都被分组到一个队列中。操作系统按顺序为每个进程分配一定的时间,即允许进程运行的时间。如果在时间片结束时进程仍在运行,则CPU将被剥夺并分配给另一个进程,如果进程在时间片内阻塞或结束,则CPU立即切换。调度程序所要做的就是维护一个就绪进程表。当进程用完时间片时,它将被移到队列的末尾。

上面的代码中存在死循环。作者希望一直用一个线程来处理业务逻辑。如果Thread.sleep(0)不使用主动放弃CPU时间片,线程资源会一直被占用。众所周知,GC 线程具有低优先级,因此Thread.sleep(0)用于帮助 GC 线程尝试竞争 CPU 时间片。但是为什么作者说可以防止long time GC呢?这就讲到JVM的垃圾回收原理了。

GC的安全点

HotSpot虚拟机为例,JVM并不会在代码指令流的任何位置暂停以启动垃圾回收,而是强制执行必须到达安全点才暂停。换句话说,在到达安全点之前,JVM 不会为 GC STOP THE WORLD

JVM 会在一些循环跳转和方法调用上设置安全点。不过,为了避免安全点过多带来的沉重负担,HotSpot虚拟机还有一个针对循环的优化措施。如果循环次数少,执行时间不宜过长。因此,默认情况下不会将使用 int 或更小数据类型作为索引值的循环放置在安全点中。这种循环称为可数循环。相应地,使用long或更大范围的数据类型作为索引值的循环称为未计数循环,将被放置在安全点。

但是,我们这里正好有一个可数循环,所以我们的代码不会放在安全点。因此,GC线程必须等到线程执行完毕,才能执行到最近的安全点。但如果使用Thread.sleep(0),则可以在代码中放置一个安全点。我们可以看下HotSpotsafepoint.cpp源码中的注释,做除了说明。

// Begin the process of bringing the system to a safepoint.
// Java threads can be in several different states and are
// stopped by different mechanisms:
//
//  1. Running interpreted
//     The interpeter dispatch table is changed to force it to
//     check for a safepoint condition between bytecodes.
//  2. Running in native code
//     When returning from the native code, a Java thread must check
//     the safepoint _state to see if we must block.  If the
//     VM thread sees a Java thread in native, it does
//     not wait for this thread to block.  The order of the memory
//     writes and reads of both the safepoint state and the Java
//     threads state is critical.  In order to guarantee that the
//     memory writes are serialized with respect to each other,
//     the VM thread issues a memory barrier instruction
//     (on MP systems).  In order to avoid the overhead of issuing
//     a memory barrier for each Java thread making native calls, each Java
//     thread performs a write to a single memory page after changing
//     the thread state.  The VM thread performs a sequence of
//     mprotect OS calls which forces all previous writes from all
//     Java threads to be serialized.  This is done in the
//     os::serialize_thread_states() call.  This has proven to be
//     much more efficient than executing a membar instruction
//     on every call to native code.
//  3. Running compiled Code
//     Compiled code reads a global (Safepoint Polling) page that
//     is set to fault if we are trying to get to a safepoint.
//  4. Blocked
//     A thread which is blocked will not be allowed to return from the
//     block condition until the safepoint operation is complete.
//  5. In VM or Transitioning between states
//     If a Java thread is currently running in the VM or transitioning
//     between states, the safepointing code will wait for the thread to
//     block itself when it attempts transitions to a new state.

可以看上面的第2点 Running in native code,而Thread.sleep(long millis)是一种native方法。

总结

Thread.sleep(0)不是什么无用的代码。sleep 方法可用于在 java 代码中放置一个安全点。可以提前在长循环中触发GC,避免GC线程长时间等待,从而避免达到拉长GC时间的目的。

以上就是Thread.sleep(0)的写法原理深入解析的详细内容,更多关于Thread.sleep(0)写法原理的资料请关注脚本之家其它相关文章!

相关文章

  • 使用restTemplate.postForEntity()的问题

    使用restTemplate.postForEntity()的问题

    这篇文章主要介绍了使用restTemplate.postForEntity()的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-09-09
  • 详解Java中的checked异常和unchecked异常区别

    详解Java中的checked异常和unchecked异常区别

    这篇文章主要介绍了详解Java中的checked异常和unchecked异常区别,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-02-02
  • Java Web实现简易图书管理系统

    Java Web实现简易图书管理系统

    这篇文章主要为大家详细介绍了Java Web实现简易图书管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-09-09
  • java分布式面试系统限流最佳实践

    java分布式面试系统限流最佳实践

    这篇文章主要介绍了java分布式面试系统限流最佳实践场景分析解答,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加薪
    2022-03-03
  • SpringBoot文件上传控制及Java 获取和判断文件头信息

    SpringBoot文件上传控制及Java 获取和判断文件头信息

    这篇文章主要介绍了SpringBoot文件上传控制的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2017-12-12
  • SpringBoot整合Swagger2的完整过程记录

    SpringBoot整合Swagger2的完整过程记录

    Swagger是一款RESTful接口的文档在线自动生成、功能测试功能框架,这篇文章主要给大家介绍了关于SpringBoot整合Swagger2的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2021-09-09
  • Java项目如何打包成Jar的实现步骤

    Java项目如何打包成Jar的实现步骤

    一般情况下我们都是使用Java项目直接部署发布,有时需要我们将写好的项目打成jar包,方便后期调用,本文主要介绍了Java项目如何打包成Jar,感兴趣的可以了解一下
    2023-11-11
  • Java读取PDF中的表格的方法示例

    Java读取PDF中的表格的方法示例

    本文主要介绍了Java读取PDF中的表格的方法示例,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-10-10
  • 三种简单排序算法(使用java实现)

    三种简单排序算法(使用java实现)

    下面小编就为大家带来一篇三种简单排序算法(使用java实现)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-07-07
  • Mybatis之@ResultMap,@Results,@Result注解的使用

    Mybatis之@ResultMap,@Results,@Result注解的使用

    这篇文章主要介绍了Mybatis之@ResultMap,@Results,@Result注解的使用,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12

最新评论