在使用ScheduledExecutorService进行周期性任务执行时,遇到一个问题:
- 如果Runnable#run()方法抛异常的话,该异常会被ScheduledExecutorService吞掉,同时ScheduledExecutorService的周期性任务会被停掉。(如果ScheduledExecutorService有多个周期性任务的话,只有这个scheduleAtFixedRate()会被停掉,其它的可以正常执行)。
import java.util.Date;
import java.util.Locale;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class Demo {
private final ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(3);
private final Runnable runnable2 = () -> System.out.printf(Locale.CHINA, "[%s][%s]Runnable2 running...\n", new Date(), Thread.currentThread().getName());
public static void main(String[] args) {
Demo d = new Demo();
d.test();
}
public void test() {
executorService.scheduleAtFixedRate(this::executeRunnable1, 0, 1000, TimeUnit.MILLISECONDS);
executorService.scheduleAtFixedRate(runnable2, 0, 2000, TimeUnit.MILLISECONDS);
}
private void executeRunnable1() {
System.out.printf(Locale.CHINA, "[%s][%s]Runnable1 running...\n", new Date(), Thread.currentThread().getName());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
throw new RuntimeException("My Exception");
} catch (Throwable t) { // Catch Throwable rather than Exception (a subclass).
System.err.println(String.format(Locale.CHINA, "[%s][%s]%s\n", new Date(), Thread.currentThread().getName(), e));
}
}
}
Solution1:
最简单的Solution是在Runnable#run()方法中添加try-catch。
Solution2:
public void test() {
ScheduledFuture<?> scheduledFuture1 = executorService.scheduleAtFixedRate(this::executeRunnable1, 0, 1000, TimeUnit.MILLISECONDS);
try {
//可以捕捉到java.lang.RuntimeException: My Exception错误,但是Runnable1不会持续执行。
scheduledFuture1.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
executorService.scheduleAtFixedRate(runnable2, 0, 2000, TimeUnit.MILLISECONDS);
}