@Scheduled注解的多线程

场景:使用spring框架自带的定时注解来实现定时任务A,定时任务B

需求:定时任务A的每次任务启动卡死,不能影响下次定时任务的触发,更不能影响定时任务B的执行

问题:spring框架自带的定时,定时任务开启成功,但所有的任务都是在同一个线程池中的同一个线程来完成的。在实际开发过程中,我们当然不希望所有的任务都运行在一个线程中,此时需要各个定时任务是相互独立的。

1.定时任务A和定时任务B是相互独立的,但是定时任务A的某个任务卡死是会影响A的下一个任务出发的,每一个任务都起一条线程去执行,要求必须每个执行完毕后才能再次执行,所以不能开启异步执行

/**
 * 实现SchedulingConfigurer ,重写configureTasks 用多线程
 */
@Component
public class SpringCornTask implements SchedulingConfigurer {

    @Autowired
    @Qualifier("updateAsyncExecutor")
    ThreadPoolTaskScheduler threadPoolTaskScheduler;

    //所有加了注解@Scheduled都是用的同一个线程池threadPoolTaskScheduler的线程,同时线程的名字updateAsyncExecutor-
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setScheduler(threadPoolTaskScheduler);
    }
}
/**
 * 创建定时任务线程池
 */
@Bean("updateAsyncExecutor")
public ThreadPoolTaskScheduler updateAsyncExecutor() {
    ThreadPoolTaskScheduler executor = new ThreadPoolTaskScheduler();
    executor.setPoolSize(3);
    executor.setThreadNamePrefix("updateAsyncExecutor-");
    //用来设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean
    executor.setWaitForTasksToCompleteOnShutdown(true);
    //该方法用来设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住。
    executor.setAwaitTerminationSeconds(9000);
    executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());

    return executor;
}
/**
 * 定时任务A
 */
@Scheduled(cron = "0 0 0/4 * * ?")
public void updateRecord() throws IOException {

    log.info("开始执行定时任务===" + new Date() + "===" + Thread.currentThread().getName());
  
    }

2.实现结果是定时任务A和定时任务B是相互独立的,而且定时任务A的某个任务卡死是不会影响A的下一个任务出发的,同时担心A和B如果共用同一个线程池,如果任务A卡死,不断起线程,不断卡死,会把线程池任务占用完毕,最终会影响到B,更何况A和B的执行频率差异很大

/**
 * 创建B的线程池
 */
@Bean("cleanAsyncExecutor")
public ThreadPoolTaskScheduler cleanAsyncExecutor() {
    ThreadPoolTaskScheduler executor = new ThreadPoolTaskScheduler();
    executor.setPoolSize(3);
    executor.setThreadNamePrefix("cleanAsyncExecutor-");
    executor.setWaitForTasksToCompleteOnShutdown(true);
    //该方法用来设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住。
    executor.setAwaitTerminationSeconds(9000);
    executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());

    return executor;
}

    //同理,创建A的线程池
    .................

/**
 * 定时任务A,同时开启异步,指定线程池updateAsyncExecutor
 */
@Async("updateAsyncExecutor")
@Scheduled(cron = "0 0 0/5 * * ?")
public void updateCompareDataRecord() throws IOException {

    log.info("开始执行定时任务A===" + new Date() + "===" + Thread.currentThread().getName());
    }
/**
 * 定时任务B,同时开启异步,指定线程池updateAsyncExecutor
 */
@Async("cleanAsyncExecutor")
@Scheduled(cron = "0 0 0 1/1 * ?")
public void cleanDataRecord() throws IOException {
    log.info("开始执行定时任务AB===" + new Date() + "===" + Thread.currentThread().getName());
    }

可以参考:spring scheduled单线程和多线程使用过程中的大坑!!不看到时候绝对后悔!! - hellodev - 博客园 (cnblogs.com)

上一篇:EasyUI - Resizable 调整大小


下一篇:EasyUi基础学习(一)—基本组件(上)