Spring Boot 中@Scheduled是单线程还是多线程?

在开发Spring Boot应用程序时,定时任务是一项常见的需求。Spring Boot提供了@Scheduled注解,可用于将方法标记为定时任务,并在预定的时间间隔内执行。那么@Scheduled注解的执行方式是单线程执行,还是多线程执行?@Scheduled注解的执行方式会不会产生线程不安全的问题?

以下总结@Scheduled注解的执行方式,并解释它在Spring Boot中的多线程行为。

一:案例演示

新建两个定时任务,一个是每2秒执行一次,一个是每3秒执行一次

@Component
public class ScheduledTest {

    @Scheduled(cron = "0/2 * * * * ? ")
    public void testTask1(){
        Thread thread = Thread.currentThread();
        String threadName = thread.getName();
        System.out.println(threadName+"-->"+ "testTask1-->"+LocalDateTime.now());
    }

    @Scheduled(cron = "0/3 * * * * ? ")
    public void testTask2(){
        Thread thread = Thread.currentThread();
        String threadName = thread.getName();
        System.out.println(threadName+"-->"+"testTask2-->"+ LocalDateTime.now());
    }
}

image-20240314003034203

发现这两个任务的线程是同一个,由此可以推测Spring Boot提供的@Scheduled注解默认是以单线程方式执行。下面看下源码:Scheduled提供的核心类ScheduledTaskRegistrar、ContextLifecycleScheduledTaskRegistrar

image-20240314003748775

ContextLifecycleScheduledTaskRegistrar 在bean实例化后会调 其父类ScheduledTaskRegistrar提供的scheduleTasks()方法,并且创建了单例的调度线程池

image-20240314003939023

image-20240314004104324

由此可见,Spring Boot提供的@Scheduled注解默认是以单线程方式执行。

有的人可能会想会不会是在同一个类中的方法导致结果是公用了同一个线程?不要猜,去验证!

image-20240314005121888

把testTask1和testTask2分别放在不同的类,结果共用同一个线程。

二:在单线程下会产生什么问题?

单线程环境下,如果某个任务处理时间很长,有可能导致其他任务阻塞。testTask1()休眠一小时模拟长时间处理任务,testTask2()一直处于阻塞状态。

@Component
public class ScheduledTest1 {

    @Scheduled(cron = "0/2 * * * * ? ")
    public void testTask1() throws InterruptedException {
        Thread thread = Thread.currentThread();
        String threadName = thread.getName();
        System.out.println("testTask1 开始执行~");
        TimeUnit.HOURS.sleep(1);
        System.out.println(threadName + "-->" + "testTask1-->" + LocalDateTime.now());
    }

    @Scheduled(cron = "0/3 * * * * ? ")
    public void testTask2() {
        Thread thread = Thread.currentThread();
        String threadName = thread.getName();
        System.out.println(threadName + "-->" + "testTask2-->" + LocalDateTime.now());
    }
}

image-20240314005903928

因此对于这种场景,我们可以考虑把@Scheduled配置成多线程环境下执行,解决@Scheduled在单线程环境下可能产生的问题。

三:@Scheduled支持多线程吗?

既然SchedulingConfigurer默认是创建了单例线程池,那我们是不是可以自定义线程池当做参数传给Scheduled呢?

@Configuration
public class ScheduleConfig implements SchedulingConfigurer {
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setScheduler(Executors.newScheduledThreadPool(5));
    }
}

案例验证代码

@Component
public class ScheduledTest6 {

    @Scheduled(cron = "0/2 * * * * ? ")
    public void testTask1() throws InterruptedException {
        Thread thread = Thread.currentThread();
        String threadName = thread.getName();
        System.out.println("testTask1 开始执行~");
        TimeUnit.HOURS.sleep(1);
        System.out.println(threadName + "-->" + "testTask1-->" + LocalDateTime.now());
    }

    @Scheduled(cron = "0/3 * * * * ? ")
    public void testTask2() {
        Thread thread = Thread.currentThread();
        String threadName = thread.getName();
        System.out.println(threadName + "-->" + "testTask2-->" + LocalDateTime.now());
    }
}

image-20240314011506586

由截图可知,有5个线程,1、2、5都正常处理testTask2任务,3、4两个线程正在处理testTask1()任务,因此多线程环境下可以解决单线程环境下可能导致的任务阻塞的问题。

更多细节可以关注我的个人主页 www.zhouy.work

相关推荐

  1. Redis单线线

    2024-03-15 07:16:03       48 阅读
  2. Redis单线线

    2024-03-15 07:16:03       45 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-15 07:16:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-15 07:16:03       100 阅读
  3. 在Django里面运行非项目文件

    2024-03-15 07:16:03       82 阅读
  4. Python语言-面向对象

    2024-03-15 07:16:03       91 阅读

热门阅读

  1. MapReduce面试重点

    2024-03-15 07:16:03       39 阅读
  2. Loader,Plugin

    2024-03-15 07:16:03       44 阅读
  3. Android如何获取蓝牙设备连接状态

    2024-03-15 07:16:03       35 阅读
  4. Spring中经典的7种设计模式源码分析

    2024-03-15 07:16:03       32 阅读
  5. 低代码与数字化工具:重塑软件开发的新范式

    2024-03-15 07:16:03       38 阅读
  6. DM_SQL

    2024-03-15 07:16:03       33 阅读
  7. Hadoop完全分布式的搭建

    2024-03-15 07:16:03       41 阅读
  8. 区块链技术的应用场景和优势

    2024-03-15 07:16:03       39 阅读
  9. Hive中的CONCAT、CONCAT_WS与COLLECT_SET函数

    2024-03-15 07:16:03       40 阅读
  10. Web框架开发-Django的路由层(URLconf)

    2024-03-15 07:16:03       41 阅读
  11. C语言scandir函数获取文件夹内容

    2024-03-15 07:16:03       39 阅读
  12. 人工智能对社会的影响

    2024-03-15 07:16:03       44 阅读
  13. html5&css&js代码 017样式示例

    2024-03-15 07:16:03       39 阅读