文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Java调度线程池ScheduledThreadPoolExecutor不执行问题分析

2023-03-02 21:03

关注

前言

最近在调试一个监控应用指标的时候发现定时器在服务启动执行一次之后就不执行了,这里用的定时器是Java的调度线程池ScheduledThreadPoolExecutor,后来经过排查发现ScheduledThreadPoolExecutor线程池处理任务如果抛出异常,会导致线程池不调度;下面就通过一个例子简单分析下为什么异常会导致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;
    }

总结

Java的ScheduledThreadPoolExecutor定时任务线程池所调度的任务中如果抛出了异常,并且异常没有捕获直接抛到框架中,会导致ScheduledThreadPoolExecutor定时任务不调度了,具体是因为当异常抛到ScheduledThreadPoolExecutor框架中时不进行下次调度时间的设置,从而导致ScheduledThreadPoolExecutor定时任务不调度。

到此这篇关于Java调度线程池ScheduledThreadPoolExecutor不执行问题分析的文章就介绍到这了,更多相关Java ScheduledThreadPoolExecutor内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯