Bootstrap

springBoot的定时任务和多线程

springboot的定时任务

定时任务有三种,现在我学习的是springboot里面的一种,是比较简单的,下面是一些dome

package com.ljquan.test.dome.test;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

/**
 * @className ScheduledService
 * @Description: 定时任务学习
 * @Author ljquan
 * @Date 2022/05/19 10:40:54
 * @Version 1.0.0
 */
@Component
@Slf4j
public class ScheduledService {
    /*
     * 这三种是单线程的
     * */
    @Scheduled(cron = "0/5 * * * * * ")
    public void test() {
        log.info("测试定时任务调度cron{}", System.currentTimeMillis());
    }
    @Scheduled(cron = "0/5 * * * * * ")
    public void test2() {
        log.info("测试定时任务调度2cron{}", System.currentTimeMillis());
    }

    @Scheduled(fixedRate = 5000)
    public void scheduled1() {
        log.info("=====>>>>>使用fixedRate{}", System.currentTimeMillis());
    }

    @Scheduled(fixedDelay = 5000)
    public void scheduled2() {
        log.info("=====>>>>>fixedDelay{}", System.currentTimeMillis());
    }
        /*
        * 在主类上使用@EnableScheduling注解开启对定时任务的支持,然后启动项目

        可以看到三个定时任务都已经执行,并且使同一个线程中串行执行,
        * 如果只有一个定时任务,这样做肯定没问题,
        * 当定时任务增多,如果一个任务卡死,会导致其他任务也无法执行。*/

}

在主类上使用@EnableScheduling注解开启对定时任务的支持,然后启动项目

package com.ljquan.test;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling
@EnableAsync
public class TestApplication {

    public static void main(String[] args) {
        SpringApplication.run(TestApplication.class, args);
        System.out.println("(♥◠‿◠)ノ゙  测试Dome启动成功   ლ(´ڡ`ლ)゙\"");
    }

}

输出结果:

(♥◠‿◠)ノ゙  测试Dome启动成功   ლ(´ڡ`ლ)゙"
2022-05-19 11:29:25.006  INFO 15868 --- [   scheduling-1] c.l.test.dome.test.ScheduledService      : 测试定时任务调度cron1652930965006
2022-05-19 11:29:25.007  INFO 15868 --- [   scheduling-1] c.l.test.dome.test.ScheduledService      : 测试定时任务调度2cron1652930965007
2022-05-19 11:29:27.843  INFO 15868 --- [   scheduling-1] c.l.test.dome.test.ScheduledService      : =====>>>>>使用fixedRate1652930967843
2022-05-19 11:29:27.843  INFO 15868 --- [   scheduling-1] c.l.test.dome.test.ScheduledService      : =====>>>>>fixedDelay1652930967843
2022-05-19 11:29:30.010  INFO 15868 --- [   scheduling-1] c.l.test.dome.test.ScheduledService      : 测试定时任务调度2cron1652930970010
2022-05-19 11:29:30.010  INFO 15868 --- [   scheduling-1] c.l.test.dome.test.ScheduledService      : 测试定时任务调度cron1652930970010
2022-05-19 11:29:32.836  INFO 15868 --- [   scheduling-1] c.l.test.dome.test.ScheduledService      : =====>>>>>使用fixedRate1652930972836
2022-05-19 11:29:32.852  INFO 15868 --- [   scheduling-1] c.l.test.dome.test.ScheduledService      : =====>>>>>fixedDelay1652930972852

可以看到,多个定时任务都是同一个线程的,如果一个定时任务出现问题,就会导致其他任务也会出现问题,所以就使用多线程的方式。

springboot的多线程 @Async 的使用、自定义Executor的配置方法

结合上面的代码

首先配置Executor,也就是重新配置我们的线程池执行器

package com.ljquan.test.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @className ExecutorConfig
 * @Description: 设置多线程的配置
 * @Author ljquan
 * @Date 2022/05/19 11:22:14
 * @Version 1.0.0
 */
@Configuration
public class ExecutorConfig {
    /**
     * 设置 ThreadPoolExecutor 的核心池大小.
     */
    private final int corePoolSize = 10;
    /**
     * 设置 ThreadPoolExecutor 的最大池大小.
     */
    private final int maxPoolSize = 200;
    /**
     * 设置 ThreadPoolExecutor 的 BlockingQueue 的容量.
     */
    private final int queueCapacity = 10;

    /**
     * 异步一
     *
     * @return {@code Executor}
     */
    @Bean
    public Executor Async1() {
        //线程池任务执行器  创建一个线程池
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //设置核心池大小
        executor.setCorePoolSize(corePoolSize);
        executor.setMaxPoolSize(maxPoolSize);
        //设置队列容量
        executor.setQueueCapacity(queueCapacity);
        //设置线程前缀
        executor.setThreadNamePrefix("测试线程demo1-");
        executor.initialize();
        return executor;
    }

    /**
     * async2
     *
     * @return {@code Executor}
     */
    @Bean
    public Executor Async2() {
        //线程池任务执行器  创建一个线程池
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //设置核心池大小
        executor.setCorePoolSize(corePoolSize);
        executor.setMaxPoolSize(maxPoolSize);
        //设置队列容量
        executor.setQueueCapacity(queueCapacity);
        //设置线程前缀
        executor.setThreadNamePrefix("222测试线程demo2-");

        // rejection-policy:当pool已经达到max size的时候,如何处理新任务
        // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
        //设置拒绝执行处理程序
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }

    //    类似的如果还有其他线程,也可以继续给其他线程配置对应的线程池
}

配置好了,就可以去使用了@Async(“Async1”)去对应的方法或者类里面去执行了,这样就相当于配置好了

 @Async("Async1")
    @Scheduled(cron = "0/5 * * * * * ")
    public void test() {
        log.info("测试定时任务调度cron{}", System.currentTimeMillis());
    }

类似于这样,就把当前的方法放进线程池里面执行了

执行结果:

(♥◠‿◠)ノ゙  测试Dome启动成功   ლ(´ڡ`ლ)゙"
2022-05-19 11:42:00.016  INFO 15908 --- [    测试线程demo1-2] c.l.test.dome.test.ScheduledService      : 测试定时任务调度2cron1652931720016
2022-05-19 11:42:00.016  INFO 15908 --- [    测试线程demo1-1] c.l.test.dome.test.ScheduledService      : 测试定时任务调度cron1652931720016
2022-05-19 11:42:00.228  INFO 15908 --- [   scheduling-1] c.l.test.dome.test.ScheduledService      : =====>>>>>使用fixedRate1652931720228
2022-05-19 11:42:00.244  INFO 15908 --- [   scheduling-1] c.l.test.dome.test.ScheduledService      : =====>>>>>fixedDelay1652931720244
2022-05-19 11:42:05.004  INFO 15908 --- [    测试线程demo1-3] c.l.test.dome.test.ScheduledService      : 测试定时任务调度cron1652931725004
2022-05-19 11:42:05.005  INFO 15908 --- [    测试线程demo1-4] c.l.test.dome.test.ScheduledService      : 测试定时任务调度2cron1652931725005
2022-05-19 11:42:05.240  INFO 15908 --- [   scheduling-1] c.l.test.dome.test.ScheduledService      : =====>>>>>使用fixedRate1652931725240

很明显的看到,这些线程都不是同一个线程了。关于springboot的多线程学习完成了。

gitee地址:
https://gitee.com/ljq4551/demo

;