Java ScheduledExecutorService在Linux下CPU占满100%且无任务执行问题
问题根源与解决方案
这是Java 8u40版本的已知bug(编号JDK-8075300),刚好被你踩中了——当ScheduledThreadPoolExecutor的核心线程数设为0时,工作线程会陷入无休的忙循环,直接把CPU拉满到100%。
为什么会触发?
你创建调度器时指定了corePoolSize=0:
executor = Executors.newScheduledThreadPool(0, (r) -> new Thread(r, "Scheduler"));
在Java 8u40的实现逻辑里,当核心线程数为0时,线程池的getTask()方法会调用DelayedWorkQueue.poll(0, TimeUnit.NANOSECONDS)(因为默认的keepAliveTime是0)。而这个版本的DelayedWorkQueue在处理超时为0的场景时,不会进入休眠等待,而是不断循环检查队列是否有任务,导致线程一直处于RUNNABLE状态,疯狂占用CPU。
你在Windows用的Java 8u45已经修复了这个bug,所以一切正常,这也侧面验证了问题的版本相关性。
怎么解决?
有两个简单靠谱的方案:
把核心线程数改成1:既然你要长期运行定时任务,保留至少1个核心线程是合理的,这样线程不会被回收,也不会触发忙循环:
executor = Executors.newScheduledThreadPool(1, (r) -> new Thread(r, "Scheduler"));升级Linux上的JDK版本:这个bug在Java 8u60及以后的版本中已经被官方修复,升级后问题自然消失。
从堆栈看问题
你提供的堆栈信息也完全符合这个bug的表现:
Thread[Scheduler,5,app] RUNNABLE CPU (msecs) = 15020099 java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.poll(ScheduledThreadPoolExecutor.java:809) java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1066) java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127) java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) java.lang.Thread.run(Thread.java:745)
线程一直卡在DelayedWorkQueue.poll方法里,且持续处于RUNNABLE状态,没有任何休眠,这就是典型的忙循环特征。
内容的提问来源于stack exchange,提问作者Tim B
相关产品推荐
相关产品推荐

