丧心病狂,竟有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秒,不就是不睡觉吗?我的第一反应是这段代码没什么用,但是看到他的注释又引起了我的兴趣。经过一番研究,看似无用的一段代码,其实大有文章。
欢迎关注微信公众号「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)
,则可以在代码中放置一个安全点。我们可以看下HotSpot
的safepoint.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)这种神仙写法?的更多相关文章
- Thread.Sleep(0) vs Sleep(1) vs Yeild
本文将要提到的线程及其相关内容,均是指 Windows 操作系统中的线程,不涉及其它操作系统. 文章索引 核心概念 Thread.Yeild Thread.Sleep(0) Thread. ...
- 【转】Thread.sleep(0)的意义
Thread.sleep(0)的意义 2012-03-23 17:47 2188人阅读 评论(2) 收藏 举报 windows算法unixthread 我们可能经常会用到 Thread.Sleep 函 ...
- Thread系列之Thread.Sleep(0)
线程这一概念,可以理解成进程中的一个小单元.这个单元是一个独立的执行单元,但是与进程中的其他线程共享进程中的内存单元. 由于Cpu资源是有限的,所以进程中的多个线程要抢占Cpu,这也导致进程中的多个线 ...
- Thread.sleep(0)的意义& 多线程
我们可能经常会用到 Thread.Sleep 函数来使线程挂起一段时间.那么你有没有正确的理解这个函数的用法呢?思考下面这两个问题: 假设现在是 2008-4-7 12:00:00.000,如果我调用 ...
- 关于Thread.Sleep(0)
看到的文章,写的不错. 我们可能经常会用到 Thread.Sleep 函数来使线程挂起一段时间.那么你有没有正确的理解这个函数的用法呢?思考下面这两个问题:假设现在是 2008-4-7 12:00:0 ...
- 对线程调度中Thread.sleep(0)的深入理解
在Java或者C#中,都会用到 Thread.Sleep()来使线程挂起一段时间.那么你有没有正确的理解这个方法的用法呢?思考下面这两个问题: 1.假设现在是 2014-8-13 17:00:00.0 ...
- Thread系列——Thread.Sleep(0)
转载自:http://www.cnblogs.com/ATually/archive/2010/10/21/1857261.html 线程这一概念,可以理解成进程中的一个小单元.这个单元是一个独立的执 ...
- 说说Thread.Sleep(0)的那些奇怪的事
写在前面 最近在弄一个传输组件,用到很多多线程的知识,其中有个问题,困扰我很久,不知道是什么原因,脑子一热,在传输过程中,添加了一句代码Thread.Sleep(0).那个问题竟然解决了,耗费我一上午 ...
- [转载]Thread.Sleep(0)妙用
原文地址:http://blog.csdn.net/lgstudyvc/article/details/9337063 来自本论坛: 我们可能经常会用到 Thread.Sleep 函数来使线程挂起一段 ...
- Thread.sleep(0)的意义
我们可能经常会用到 Thread.Sleep 函数来使线程挂起一段时间.那么你有没有正确的理解这个函数的用法呢?思考下面这两个问题: 假设现在是 2008-4-7 12:00:00.000,如果我调用 ...
随机推荐
- HBase1.4.6安装搭建及shell命令使用
HBase1.4.6安装搭建 目录 HBase1.4.6安装搭建 一.前期准备(Hadoop,zookeeper,jdk) 搭建Hbase 1.上传解压 2.配置环境变量 3.修改hbase-env. ...
- UVA12186 工人的请愿书 Another Crisis (树形DP)
dp[i]表示要让i向上级发请愿书,最少需要多少个工人递交请愿书,因为要取前T%最小的,所以还要将i的子节点排序(这里用vector实现),取前c个最小的作为dp[i]的值. 这里用dfs可以省去dp ...
- SpringBoot+MyBatis Plus对Map中Date格式转换的处理
在 SpringBoot 项目中, 如何统一 JSON 格式化中的日期格式 问题 现在的关系型数据库例如PostgreSQL/MySQL, 都已经对 JSON 类型提供相当丰富的功能, 项目中对于不需 ...
- KubeEdge 1.12版本发布,稳定性、安全性、可扩展性均带来大幅提升
摘要:2022年9月29日,KubeEdge发布1.12版本.新版本新增多个增强功能,在扩展性.稳定性.安全性上均有大幅提升. 本文分享自华为云社区<KubeEdge 1.12版本发布,稳定性. ...
- JVM中的方法区
JVM中的方法区 方法区存储什么? 用于存储已被虚拟机加载的类型信息.常量.静态变量.即时编译器编译后的代码缓存 1.类型信息 对每个加载的类型(类class.接口interface.枚举.注解)jv ...
- 五、docker网络
一.Docker 网络 docker网络主要是解决容器联网问题,也是我们使用容器中最重要的一个环节,如果容器没有网络则无法向网络中提供服务. 网络管理命令:docker network [root@z ...
- PCA降维的原理及实现
PCA可以将数据从原来的向量空间映射到新的空间中.由于每次选择的都是方差最大的方向,所以往往经过前几个维度的划分后,之后的数据排列都非常紧密了, 我们可以舍弃这些维度从而实现降维 原理 内积 两个向量 ...
- 论文笔记 - PRISM: A Rich Class of Parameterized Submodular Information Measures for Guided Subset Selection
Motivation 与 Active Learning 类似,Target Learning 致力于 挑选外卖更"感兴趣"的数据,即人为为更重要的数据添加 bias.例如我们当前 ...
- Django开发汇总
基本配置 # 设置数据库为使用的mysql DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'libr ...
- Excel中的VLOOKUP函数
VLOOKUP函数是Excel中的一个纵向查找函数,功能是按列查找,最终返回该列所需查询序列所对应的值. 该函数的语法规则如下: VLOOKUP(lookup_value,table_array,co ...