

丧心病狂,竟有Thread.sleep(0)这种神仙写法? - JAVA旭阳
source link: https://www.cnblogs.com/alvinscript/p/17009170.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

丧心病狂,竟有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旭阳」交流和学习
更多学习资料请移步:程序员成神之路
Recommend
-
7
12个怪怪的设计,没有最怪,只有更怪!文章转载自:TODAY DESIGN ID:TODAY_DESIGN 编辑:dada
-
3
V2EX › 游戏开发 [求助] 这种在线 CS 是什么神仙技术?
-
4
本篇文章主要讲解下Map家族中3个相对冷门的容器,分别是WeakHashMap、EnumMap、IdentityHashMap, 想必大家在平时的工作中也很少用到,或者压根不知道他们的特性以及适用场景,本篇文章就带你一探究竟。 WeakHashMap WeakHashMap称...
-
5
注解想必大家都用过,也叫元数据,是一种代码级别的注释,可以对类或者方法等元素做标记说明,比如Spring框架中的@Service,@Component等。那么今天我想问大家的是类被继承了,注解能否继承呢?可能会和大家想的不一样,感兴趣的可以往下...
-
8
大家项目中如果有生成随机数的需求,我想大多都会选择使用Random来实现,它内部使用了CAS来实现。 实际上,JDK1.7之后,提供了另外一个生成随机数的类ThreadLocalRandom,那么他们二者之间的性能是怎么样的呢? Random的使用 Rand...
-
4
在使用spring的过程中,我们有没有发现它的扩展能力很强呢? 由于这个优势的存在,使得spring具有很强的包容性,所以很多第三方应用或者框架可以很容易的投入到spring的怀抱中。今天我们主要来学习Spring中很常用的11个扩展点,你用过几个呢?
-
6
欢迎关注微信公众号「JAVA旭阳」交流和学习 IntelliJ目前已经成为市面上最受欢迎的Java开发工具,这得益于里面非常丰富的插件机制。本文我将分享在日常开发中我经常使用的5个插件,它们可以帮助您提高工作效率。...
-
9
作为一名java开发程序员,不知道大家有没有遇到过一些匪夷所思的bug。这些错误通常需要您几个小时才能解决。当你找到它们的时候,你可能会默默地骂自己是个傻瓜。是的,这些可笑的bug基本上都是你忽略了一些基础知识造成的。其实都是很低级的错误。今天,我总结一些...
-
8
作为后端开发人员,我们总是在编写各种API,无论是为前端web提供数据支持的HTTP REST API ,还是提供内部使用的RPC API。这些API在服务初期可能表现不错,但随着用户数量的增长,一开始响应很快的API越来越慢,直到用户抱怨:“你的系统太...
-
6
微服务架构如今非常的流行,这个架构下可能经常会遇到“双写”的场景。双写是指您的应用程序需要在两个不同的系统中更改数据的情况,比如它需要将数据存储在数据库中并向消息队列发送事件。您需要保证这两个操作都会成功。如果两个操作之一失败,您的系统可能会变得不...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK