美文网首页
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