美文网首页
springboot + @Scheduled 多任务并发

springboot + @Scheduled 多任务并发

作者: yuan_dongj | 来源:发表于2018-05-02 17:28 被阅读0次

    问题

    @Scheduled默认为单线程,开启多个任务时,任务的执行时机会受上一个任务执行时间的影响。

    @Component
    public class ScheduledTasks {
        private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd  HH:mm:ss");
    
        @Scheduled(fixedDelay = 1000)
        public void first() throws InterruptedException {
            System.out.println("第一个定时任务开始 : " + sdf.format(new Date()) + "\r\n线程 : " + Thread.currentThread().getName());
            System.out.println();
            Thread.sleep(1000 * 5); //模拟第一个任务执行的时间
        }
    
        @Scheduled(fixedDelay = 1000)
        public void second() {
            System.out.println("第二个定时任务开始 : " + sdf.format(new Date()) + "\r\n线程 : " + Thread.currentThread().getName());
            System.out.println();
        }
    }
    
    测试.png

    解决方法

    在task上加@EnableAsync注解,在任务方法上加@Async注解

    @Component
    @EnableAsync
    public class ScheduledTasks {
        private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd  HH:mm;ss");
    
        @Async
        @Scheduled(fixedDelay = 1000)
        public void first() throws InterruptedException {
            System.out.println("第一个定时任务开始 : " + sdf.format(new Date()) + "\r\n线程 : " + Thread.currentThread().getName());
            System.out.println();
            Thread.sleep(1000 * 5);
        }
    
        @Async
        @Scheduled(fixedDelay = 1000)
        public void second() {
            System.out.println("第二个定时任务开始 : " + sdf.format(new Date()) + "\r\n线程 : " + Thread.currentThread().getName());
            System.out.println();
        }
    }
    
    测试.png

    另外,由于开启了多线程,第一个任务的执行时机也不受其本身执行时间的限制,需要注意数据幂等性。

    解决方法2

    /**
    * @author YuanChong
    * @create 2019-06-20 14:39
    * @desc
    */
    @Configuration
    public class ScheduleConfig implements SchedulingConfigurer {
    
       @Autowired
       private Executor executor;
    
       private final ThreadFactory threadFactory = new BasicThreadFactory.Builder().namingPattern("hualala-scheduled-task-%d").build();
    
       @Override
       public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
           taskRegistrar.setScheduler(executor);
       }
    
       @Bean(destroyMethod = "shutdown")
       public Executor taskExecutor() {
           return Executors.newScheduledThreadPool(8, threadFactory);
       }
    }
    

    这种方式的好处在于单任务自己是串行,任务与任务之间是并行。

    @Scheduled属性

    @Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Repeatable(Schedules.class)
    public @interface Scheduled {
        String cron() default "";
    
        String zone() default "";
    
        long fixedDelay() default -1L;
    
        String fixedDelayString() default "";
    
        long fixedRate() default -1L;
    
        String fixedRateString() default "";
    
        long initialDelay() default -1L;
    
        String initialDelayString() default "";
    }
    

    单线程下:

    • cron每一次执行完成后,再遇到给定的规则时间点上触发。
    • fixedDelay受上一次执行时间的影响,再间隔设置时间后执行。
    • fixedRate安装固定的速率执行,如果一段时间内任务阻塞,会积攒任务次数,在恢复时一次性执行完成。
    image.png

    另,initialDelay属性可同时配合上面属性使用,用于初次执行前等待的时间。

    相关文章

      网友评论

          本文标题:springboot + @Scheduled 多任务并发

          本文链接:https://www.haomeiwen.com/subject/wcvcrftx.html