Java调度线程池ScheduledThreadPoolExecutor不执行问题怎么解决

寻技术 JAVA编程 2023年07月12日 73

本篇内容主要讲解“Java调度线程池ScheduledThreadPoolExecutor不执行问题怎么解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java调度线程池ScheduledThreadPoolExecutor不执行问题怎么解决”吧!

    ScheduledThreadPoolExecutor不调度分析

    示例程序

    在示例程序可以看到当计数器中的计数达到5的时候就会主动抛出一个异常,抛出异常后

    ScheduledThreadPoolExecutor
    就不调度了。
    public class ScheduledTask {
        private static final AtomicInteger count = new AtomicInteger(0);
        private static final ScheduledThreadPoolExecutor SCHEDULED_TASK = new ScheduledThreadPoolExecutor(
                1, new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                Thread t = new Thread(Thread.currentThread().getThreadGroup(), r, "sc-task");
                t.setDaemon(true);
                return t;
            }
        });
        public static void main(String[] args) throws InterruptedException {
            CountDownLatch latch = new CountDownLatch(1);
            SCHEDULED_TASK.scheduleWithFixedDelay(() -> {
                System.out.println(111);
                if (count.get() == 5) {
                    throw new IllegalArgumentException("my exception");
                }
                count.incrementAndGet();
            }, 0, 5, TimeUnit.SECONDS);
            latch.await();
        }
    }

    源码分析

    ScheduledThreadPoolExecutor#run

    run方法内部首先判断任务是不是周期性的任务,如果不是周期性任务通过

    ScheduledFutureTask.super.run();
    执行任务;如果状态是运行中或shutdown,取消任务执行;如果是周期性的任务,通过
    ScheduledFutureTask.super.runAndReset()
    执行任务并且重新设置状态,成功了就会执行
    setNextRunTime
    设置下次调度的时间,问题就是出现在
    ScheduledFutureTask.super.runAndReset()
    ,这里执行任务出现了异常,导致结果为false,就不进行下次调度时间设置等
            public void run() {
                boolean periodic = isPeriodic();
                if (!canRunInCurrentRunState(periodic))
                    cancel(false);
                else if (!periodic)
                    ScheduledFutureTask.super.run();
                else if (ScheduledFutureTask.super.runAndReset()) {
                    setNextRunTime();
                    reExecutePeriodic(outerTask);
                }
            }

    *FutureTask#runAndReset

    在线程任务执行过程中抛出异常,然后

    catch
    到了异常,最终导致这个方法返回false,然后
    ScheduledThreadPoolExecutor#run
    就不设置下次执行时间了,代码
    c.call(); 
    抛出异常,跳过
    ran = true;
    代码,最终
    runAndReset
    返回false。
        protected boolean runAndReset() {
            if (state != NEW ||
                !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                             null, Thread.currentThread()))
                return false;
            boolean ran = false;
            int s = state;
            try {
                Callable<V> c = callable;
                if (c != null && s == NEW) {
                    try {
                        c.call(); // don't set result
                        ran = true;
                    } catch (Throwable ex) {
                        setException(ex);
                    }
                }
            } finally {
                // runner must be non-null until state is settled to
                // prevent concurrent calls to run()
                runner = null;
                // state must be re-read after nulling runner to prevent
                // leaked interrupts
                s = state;
                if (s >= INTERRUPTING)
                    handlePossibleCancellationInterrupt(s);
            }
            return ran && s == NEW;
        }
    关闭

    用微信“扫一扫”