商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > SpringBoot定时任务+自定义线程池实践

SpringBoot定时任务+自定义线程池实践

  发布于2026-05-21 阅读(0)

扫一扫,手机访问

在Ja va企业级开发中,定时任务几乎是绕不开的刚需。无论是深夜同步第三方数据,还是定期清理冗余信息,一个稳定可靠的调度机制都是项目平稳运行的基石。好在,如果你正在使用SpringBoot,这件事会变得异常简单——框架已经为我们封装好了全套的定时任务组件。

启动定时任务

开启SpringBoot的定时任务功能,只需要在启动类上添加一个注解。没错,就这么简单。

@SpringBootApplication
@EnableScheduling
public class ScheduleTestApplication {

    public static void main(String[] args) {
        SpringApplication.run(ScheduleTestApplication.class, args);
    }

}

加上@EnableScheduling,定时任务的引擎就启动了。

创建定时任务

SpringBoot的调度器支持四种主流的任务触发方式:

  • fixedRate:固定频率执行。比如设定每3秒执行一次,它会严格按照这个节奏来。
  • fixedDelay:固定延迟执行。它关注的是上一次任务成功结束后,再间隔指定的时间执行下一次。
  • initialDelay:初始延迟。项目启动后先等待一段时间,再开始执行定时任务,之后则按固定频率或间隔运行。
  • cron:使用Cron表达式。这是最强大、最灵活,也是在企业开发中最常用的一种方式。

可以说,掌握了Cron表达式,就等于掌握了SpringBoot定时任务的核心。

使用cron表达式

下面是一个典型的例子,使用@Scheduled注解配合Cron表达式,实现每5秒执行一次的任务。

@Component
public class ScheduleTask {

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    //每隔5秒执行一次该方法
    @Scheduled(cron = "*/5 * * * * ?")
    public void testScheduleTask() {
        System.out.println("SpringBoot的定时任务" + Thread.currentThread().getName() + sdf.format(new Date()));
    }

}

SpringBoot定时任务+自定义线程池实践

@Schedule默认线程池大小

这里有个容易被忽略的细节:@Scheduled默认使用的是单线程执行器。怎么验证呢?我们可以设计一个实验。

@Component
public class ScheduleTask {

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    //固定2秒执行一次该方法
    @Scheduled(fixedRate = 2000)
    public void testScheduleTask() {
        try{
            Thread.sleep(6000);
            System.out.println("SpringBoot的定时任务" + Thread.currentThread().getName() + sdf.format(new Date()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

SpringBoot定时任务+自定义线程池实践

从执行结果可以看到,虽然设置了fixedRate = 2000(期望每2秒执行一次),但因为方法内部睡眠了6秒,而任务又是在同一个名为“scheduling-1”的线程中串行执行的,所以实际输出间隔变成了6秒。这说明,默认情况下所有定时任务都在一个线程队列里排队。在任务不多、执行迅速的场景下这没问题,但一旦任务耗时较长或者任务数量多,就可能导致后续任务被阻塞,无法按时执行。

异步执行定时任务

解决上述阻塞问题的一个直接方法是让任务异步执行。SpringBoot提供了@Async注解来帮忙。

@Component
@EnableAsync
public class ScheduleTask {

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Async
    @Scheduled(fixedRate = 2000)
    public void testScheduleTask() {
        try{
            Thread.sleep(6000);
            System.out.println("SpringBoot的定时任务" + Thread.currentThread().getName() + sdf.format(new Date()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

SpringBoot定时任务+自定义线程池实践

加上@Async后,效果立竿见影。每个任务都由不同的线程执行,尽管方法内部仍然睡眠6秒,但任务触发频率严格遵循了2秒的设定,实现了并行处理。

手动实现自定义任务线程池

使用@Async确实方便,但它的线程池配置是全局默认的。对于追求精细控制的开发者来说,手动配置一个专属的线程池是更优的选择。这样可以更好地管理线程数、队列容量和拒绝策略,以适应特定的业务负载。

@Component
public class AsyncScheduledTaskConfig {

    @Bean
    public Executor myAsync() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //最大线程数
        executor.setMaxPoolSize(100);
        //核心线程数
        executor.setCorePoolSize(10);
        //任务队列的大小
        executor.setQueueCapacity(10);
        //线程前缀名
        executor.setThreadNamePrefix("god-jiang-");
        //线程存活时间
        executor.setKeepAliveSeconds(30);

        /**
         * 拒绝处理策略
         * CallerRunsPolicy():交由调用方线程运行,比如 main 线程。
         * AbortPolicy():直接抛出异常。
         * DiscardPolicy():直接丢弃。
         * DiscardOldestPolicy():丢弃队列中最老的任务。
         */
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
        //线程初始化
        executor.initialize();
        return executor;
    }
}

配置好线程池后,在@Async注解中指定其名称即可使用。

@Component
@EnableAsync
public class ScheduleTask {

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Async("myAsync")
    @Scheduled(fixedRate = 2000)
    public void testScheduleTask() {
        try{
            Thread.sleep(6000);
            System.out.println("SpringBoot的定时任务" + Thread.currentThread().getName() + sdf.format(new Date()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

SpringBoot定时任务+自定义线程池实践

现在,执行任务的线程都带上了自定义的前缀“god-jiang-”。这样做的好处非常明显:在复杂的微服务环境中,当需要排查性能问题或错误日志时,带有明确标识的线程名能让你快速定位问题源头。

总结

总的来说,SpringBoot的@Scheduled注解让定时任务的开发变得极其简洁。从基础的Cron表达式使用,到意识到默认单线程池的潜在瓶颈,再到通过@Async实现异步,最终进阶到自定义线程池以获得完全的控制权——这条路径清晰地展示了如何构建一个健壮、高效且易于维护的定时任务体系。这套组合拳,足以应对绝大多数企业级应用对定时调度的需求。

本文转载于:https://www.jb51.net/program/363487k7p.htm 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注