【多线程编程】--任务调度@Scheduled、ScheduledThreadPoolExecutor、quartz、xxl-job

目录

  • 一、springboot集成@Scheduled注解
    • 1.1、集成@Scheduled注解方法
    • 1.2、集成@Scheduled注解优劣点
    • 1.3、集成@Scheduled注解改进
    • 1.5、@Scheduled注解+@Async注解 能否解决单线程问题
    • 1.6、集成@Scheduled注解优缺点汇总
  • 二、springboot使用ScheduledThreadPoolExecutor定时调度
    • 2.1、ScheduleAtFixedRate方法
    • 2.2、ScheduleWithFixedDelay方法
  • 三、springboot集成quartz
    • 3.1、简单实现
    • 3.2、quartz优缺点
  • 四、springboot集成xxl-job
    • 4.1、编译启动xxl-job-admin
    • 4.2、springboot集成xxl-job
  • 四、任务调度技术的选择

说明
定时任务调度在很多场景中应用,并且市场上也有很多技术栈(如@Scheduled、ScheduledThreadPoolExecutor、quartz等),下面就以Springboot集成这些定时任务调度技术进行对比,比较在实际应用中的优劣。

一、springboot集成@Scheduled注解

1.1、集成@Scheduled注解方法

要想开启@Scheduled,只需要Application启动类增加@EnableScheduling注解即可。

@SpringBootApplication(scanBasePackages= {
   "com.wwy"})
@EnableScheduling  //开启定时任务功能
public class LearnitemApplication extends SpringBootServletInitializer {
   
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder){
   
        return builder.sources(LearnitemApplication.class);
    }
    public static void main(String[] args) {
   
        SpringApplication.run(LearnitemApplication.class, args);
    }
}

具体使用过程

@Component
public class ScheduleTaskServer {
   

    /**
     * cron 每10秒执行
     */
    @Scheduled(cron = "0/1 * * * * *")
    public void cronV1(){
   
        System.out.println("cronV1 "+Thread.currentThread().getName()+" 执行时间start:"+new Date());
        try {
   
            Thread.sleep(5000);
        } catch (InterruptedException e) {
   
            e.printStackTrace();
        }
    }
    @Scheduled(cron = "0/1 * * * * *")
    public void cronV2(){
   
        System.out.println("cronV2 "+Thread.currentThread().getName()+" 执行时间start:"+new Date());
    }
 }

结果:

 * cronV2 scheduling-1 执行时间start:Mon Jan 10 11:18:35 CST 2022
     * cronV1 scheduling-1 执行时间start:Mon Jan 10 11:18:35 CST 2022
     * cronV2 scheduling-1 执行时间start:Mon Jan 10 11:18:40 CST 2022
     * cronV1 scheduling-1 执行时间start:Mon Jan 10 11:18:41 CST 2022
     * cronV2 scheduling-1 执行时间start:Mon Jan 10 11:18:46 CST 2022
     * cronV1 scheduling-1 执行时间start:Mon Jan 10 11:18:47 CST 2022
     * cronV2 scheduling-1 执行时间start:Mon Jan 10 11:18:52 CST 2022
     * cronV1 scheduling-1 执行时间start:Mon Jan 10 11:18:53 CST 2022

结果分析:
即使开启两个@Scheduled,也是同一个线程【scheduling-1】执行,说明@Scheduled注解是单线程。
本身 cronV2先执行完,然后等待cronV1执行完,才能执行cronV2。

1.2、集成@Scheduled注解优劣点

存在问题:
(1)、单线程执行,如果某个任务阻塞会影响其他任务;
(2)、某个任务失败,后续还会继续执行,并且任务随着系统服务启动而开启,不能终止或中途添加;
(3)、只能适用于单机服务架构,不适合分布式场景;

1.3、集成@Scheduled注解改进

针对上面第一个存在问题,可以使用多线程来解决。--------------采用多线程解决方法有两种:(1)、通过配置设置Scheduled为多线程;(2)、自己维护线程池。

通过配置设置Scheduled为多线程

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

自己维护线程池

@Component
public class AsyncScheduleTaskServer {
   

    private static ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(
            2,2,1000,TimeUnit.SECONDS,new LinkedBlockingDeque<>(100));

    @Scheduled(cron = "0/1 * * * * *")
    public void asyncCronV1(){
   
        poolExecutor.execute(()->{
   
            System.out.println("async  CronV1 "+Thread.currentThread().getName()+" 执行时间start:"+new Date());
            try {
   
                Thread.sleep(3000);
            } catch (InterruptedException e) {
   
                e.printStackTrace();
            }
        });
    }

    @Scheduled(cron = "0/1 * * * * *")
    public void asyncCronV2(){
   
        poolExecutor.execute(()->{
   
            System.out.println("async  CronV2 "+Thread.currentThread().getName()

你可能感兴趣的:(多线程编程,java)