From 5ff8e41de202e22210d576bfa90626b435b157cd Mon Sep 17 00:00:00 2001 From: orangej Date: Sun, 26 Sep 2021 10:11:03 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=EF=BC=9A=E6=8D=95=E8=8E=B7?= =?UTF-8?q?=20ScheduledThreadPoolExecutor=20=E6=89=80=E6=9C=89=E4=B8=9A?= =?UTF-8?q?=E5=8A=A1=E5=BC=82=E5=B8=B8=EF=BC=8C=E9=98=B2=E6=AD=A2=E5=85=B6?= =?UTF-8?q?=E6=84=8F=E5=A4=96=E7=BB=88=E6=AD=A2=E8=B0=83=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/docs/schedule.md | 2 ++ .../schedule/JbootSafeRunnable.java | 28 +++++++++++++++++++ .../schedule/JbootScheduleManager.java | 7 ++++- 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 src/main/java/io/jboot/components/schedule/JbootSafeRunnable.java diff --git a/doc/docs/schedule.md b/doc/docs/schedule.md index 6ff2bada..5c09c61a 100644 --- a/doc/docs/schedule.md +++ b/doc/docs/schedule.md @@ -53,6 +53,8 @@ public class MyTask implements Runnable { } } ``` +注意:由于 jdk `ScheduledThreadPoolExecutor` 自身实现的问题,任务的 run 方法如果抛出异常,会造成线程池停止调度, +请务必在任务的 run 方法中使用 try catch 自行捕捉异常。 **方案3:** 使用 JFinal 自带的任务调度方案,参考文档:https://www.jfinal.com/doc/9-1 diff --git a/src/main/java/io/jboot/components/schedule/JbootSafeRunnable.java b/src/main/java/io/jboot/components/schedule/JbootSafeRunnable.java new file mode 100644 index 00000000..94270c88 --- /dev/null +++ b/src/main/java/io/jboot/components/schedule/JbootSafeRunnable.java @@ -0,0 +1,28 @@ +package io.jboot.components.schedule; + +import com.jfinal.log.Log; + +/** + * 使用 try catch 包裹业务代码,防止业务现场抛出异常导致 ScheduledThreadPoolExecutor 终止调度 + * + * @author orangej + * @since 2021-9-26 + */ +public class JbootSafeRunnable implements Runnable { + private static final Log LOG = Log.getLog(JbootSafeRunnable.class); + + private Runnable job; + + public JbootSafeRunnable(Runnable job) { + this.job = job; + } + + @Override + public void run() { + try { + job.run(); + } catch (Throwable ex) { + LOG.error(ex.toString(), ex); + } + } +} diff --git a/src/main/java/io/jboot/components/schedule/JbootScheduleManager.java b/src/main/java/io/jboot/components/schedule/JbootScheduleManager.java index e5cf0a1f..54d67d54 100644 --- a/src/main/java/io/jboot/components/schedule/JbootScheduleManager.java +++ b/src/main/java/io/jboot/components/schedule/JbootScheduleManager.java @@ -53,7 +53,7 @@ public class JbootScheduleManager { public JbootScheduleManager() { config = Jboot.config(JbooScheduleConfig.class); - fixedScheduler = new ScheduledThreadPoolExecutor(config.getPoolSize(),new NamedThreadFactory("jboot-scheduler")); + fixedScheduler = new ScheduledThreadPoolExecutor(config.getPoolSize(), new NamedThreadFactory("jboot-scheduler")); File cron4jProperties = new File(PathKit.getRootClassPath(), config.getCron4jFile()); cron4jPlugin = cron4jProperties.exists() @@ -90,6 +90,10 @@ public class JbootScheduleManager { Runnable executeRunnable = runnableClass.getAnnotation(EnableDistributedRunnable.class) == null ? runnable : new JbootDistributedRunnable(runnable, fixedDelayJob.period()); + + // ScheduledThreadPoolExecutor 线程池在遇到未捕获的异常时会终止调度 + // JbootSafeRunnable 可以捕捉业务代码异常,防止线程池意外终止调度 + executeRunnable = new JbootSafeRunnable(executeRunnable); try { scheduleRunnableCache.put(runnableClass, executeRunnable); // modified by lixin 08.08, 用于remove fixedScheduler @@ -106,6 +110,7 @@ public class JbootScheduleManager { Runnable executeRunnable = runnableClass.getAnnotation(EnableDistributedRunnable.class) == null ? runnable : new JbootDistributedRunnable(runnable, fixedRateJob.period()); + executeRunnable = new JbootSafeRunnable(executeRunnable); try { scheduleRunnableCache.put(runnableClass, executeRunnable); // modified by lixin 08.08, 用于 remove fixedScheduler -- Gitee