1.问题描述
在使用ScheduledThreadPoolExecutor的时候,可以用来周期性地执行任务。但是不知道什么原因,发现过一段时间任务不执行了。
2.解决思路
使用jstack命令先看一下进程的状态:
"scheduled-pool-0" #11 prio=5 os_prio=0 tid=0x000000001c370800 nid=0x31bc waitin
g on condition [0x000000001cf2e000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x0000000782137a90> (a java.util.concurrent.lock
s.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject
.await(AbstractQueuedSynchronizer.java:2039)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.tak
e(ScheduledThreadPoolExecutor.java:1081)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.tak
e(ScheduledThreadPoolExecutor.java:809)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.ja
va:1067)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.
java:1127)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor
.java:617)
at java.lang.Thread.run(Thread.java:745)
通过上面信息我们可以看到scheduled线程,线程处于WAITING状态,原因是在执行DelayedWorkQueue.take()方法后,调用了await()方法,我们看一下源码:
原因是在获取队列的数据时,没有获取到,很明显是不生产任务了。源码分析可以参考这篇文章:
https://www.jianshu.com/p/f9c4565419e9?from=timeline&isappinstalled=0
用代码测试了一下:
package com.lwq.www;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* @author: LWQ
* @create: 2019/10/16
* @description: ScheduledThreadPoolExectuorTest
**/
public class ScheduledThreadPoolExectuorTest {
public static int count = 0;
public static void main(String[] args) {
ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder().setNameFormat("scheduled-pool-%d").build());
scheduledThreadPoolExecutor.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
if (count > 2) {
invokeA(null);
} else {
invokeA(count + "");
}
count = count + 1;
}
}, 0, 5, TimeUnit.SECONDS);
}
public static void invokeA(String str) {
System.out.println(Integer.valueOf(str));
}
}
执行结果为:
0
1
2
在count>2时,会抛出异常后,然后任务不再周期性执行了。
3.结论
通过查看scheduleAtFixedRate的jdk文档,有一句如下:
If any execution of the task encounters an exception, subsequent executions are suppressed.
如果在任务的执行中遇到异常,后续执行被取消。
ScheduledThreadPoolExecutor的最优实践:将所有执行代码用try-catch包裹。