前言

最近在网上看到了一段代码,让我感到很迷茫。他在代码中使用了 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秒,不就是不睡觉吗?我的第一反应是这段代码没什么用,但是看到他的注释又引起了我的兴趣。经过一番研究,看似无用的一段代码,其实大有文章。

欢迎关注微信公众号「JAVA旭阳」交流和学习

探索分析

为了找到原因,首先去看下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时间的目的。

欢迎关注微信公众号「JAVA旭阳」交流和学习

更多学习资料请移步:程序员成神之路

丧心病狂,竟有Thread.sleep(0)这种神仙写法?的更多相关文章

  1. Thread.Sleep(0) vs Sleep(1) vs Yeild

    本文将要提到的线程及其相关内容,均是指 Windows 操作系统中的线程,不涉及其它操作系统. 文章索引 核心概念 Thread.Yeild       Thread.Sleep(0) Thread. ...

  2. 【转】Thread.sleep(0)的意义

    Thread.sleep(0)的意义 2012-03-23 17:47 2188人阅读 评论(2) 收藏 举报 windows算法unixthread 我们可能经常会用到 Thread.Sleep 函 ...

  3. Thread系列之Thread.Sleep(0)

    线程这一概念,可以理解成进程中的一个小单元.这个单元是一个独立的执行单元,但是与进程中的其他线程共享进程中的内存单元. 由于Cpu资源是有限的,所以进程中的多个线程要抢占Cpu,这也导致进程中的多个线 ...

  4. Thread.sleep(0)的意义& 多线程

    我们可能经常会用到 Thread.Sleep 函数来使线程挂起一段时间.那么你有没有正确的理解这个函数的用法呢?思考下面这两个问题: 假设现在是 2008-4-7 12:00:00.000,如果我调用 ...

  5. 关于Thread.Sleep(0)

    看到的文章,写的不错. 我们可能经常会用到 Thread.Sleep 函数来使线程挂起一段时间.那么你有没有正确的理解这个函数的用法呢?思考下面这两个问题:假设现在是 2008-4-7 12:00:0 ...

  6. 对线程调度中Thread.sleep(0)的深入理解

    在Java或者C#中,都会用到 Thread.Sleep()来使线程挂起一段时间.那么你有没有正确的理解这个方法的用法呢?思考下面这两个问题: 1.假设现在是 2014-8-13 17:00:00.0 ...

  7. Thread系列——Thread.Sleep(0)

    转载自:http://www.cnblogs.com/ATually/archive/2010/10/21/1857261.html 线程这一概念,可以理解成进程中的一个小单元.这个单元是一个独立的执 ...

  8. 说说Thread.Sleep(0)的那些奇怪的事

    写在前面 最近在弄一个传输组件,用到很多多线程的知识,其中有个问题,困扰我很久,不知道是什么原因,脑子一热,在传输过程中,添加了一句代码Thread.Sleep(0).那个问题竟然解决了,耗费我一上午 ...

  9. [转载]Thread.Sleep(0)妙用

    原文地址:http://blog.csdn.net/lgstudyvc/article/details/9337063 来自本论坛: 我们可能经常会用到 Thread.Sleep 函数来使线程挂起一段 ...

  10. Thread.sleep(0)的意义

    我们可能经常会用到 Thread.Sleep 函数来使线程挂起一段时间.那么你有没有正确的理解这个函数的用法呢?思考下面这两个问题: 假设现在是 2008-4-7 12:00:00.000,如果我调用 ...

随机推荐

  1. CPS攻击案例(一)——基于脉冲宽度调制PWM的无人机攻击

    ​  本文系原创,转载请说明出处 Please Subscribe Wechat Official Account:信安科研人,获取更多的原创安全资讯 原论文链接:sec22-dayanikli.pd ...

  2. HDU2844 Coins(多重背包)

    多重背包就是每种物品有数量限制时求解最大价值. 如果一种物品数量和重量之积超过背包容量,可视为完全背包:其余情况通过二进制拆分,将几个数量的物品看成一个,转化为01背包求解. 按照这种思路代码是这样的 ...

  3. 洛谷P1719 最大加权矩形 (DP/二维前缀和)

    题目描述也没啥好说的,就是给你个你n*n的矩形(带权),求其中最大权值的子矩阵. 首先比较好想的就是二维前缀和,n<=120,所以可以用暴力. 1 #include<bits/stdc++ ...

  4. GCN的原理及其代码实现

    图数据的特征性质 图像数据是一种特殊的图数据,图像数据是标准的2D网格结构图数据.图像数据的CNN卷积神经网络算法不能直接用在图数据上,原因是图数据具有以下特殊性. 节点分布不均匀:图像数据及网格数据 ...

  5. Goland Socket 服务

    客户端发送消息 并接收服务端消息 package main import ( "fmt" "net" ) func main() { // conn, err ...

  6. python-D1-typora软件和计算机入门1

    一 typora软件 typora是一款目前非常火爆文本编辑器 1.1 安装 尽量安装在非系统盘符及设置为短路径,方便后面查找 1.2 文件路径 在计算机上就是一个资源的定位坐标,表现为具体在哪里,例 ...

  7. 后端框架学习-----mybatis(使用mybatis框架遇到的问题)

    1.配置文件没有注册(解决:在核心配置文件中注册mapper,注册有三种形式.资源路径用斜杆,包和类用点) <mappers> <!--每一个mapper.xml文件都需要在myba ...

  8. 线性表的基本操作(C语言实现)

    文章目录 这里使用的工具是DEV C++ 可以借鉴一下 实现效果 顺序存储代码实现 链式存储存储实现 这里使用的工具是DEV C++ 可以借鉴一下 一.实训名称 线性表的基本操作 二.实训目的 1.掌 ...

  9. Codeforces Round #820 (Div. 3) A-G

    比赛链接 A 题解 知识点:模拟 时间复杂度 \(O(1)\) 空间复杂度 \(O(1)\) 代码 #include <bits/stdc++.h> #define ll long lon ...

  10. JavaWeb实战:基础CRUD+批量删除+分页+条件

    技术栈及相关参考资料: MyBatis基础 Servlet基础 ServletRequest和ServletResponse MVC模式和三层架构 AJAX基础+Axios基础 Vue前端框架 Ele ...