@Schedule创建的定时任务默认单线程的同步执行,虽然可以通过SchedulingConfigurer指定线程的个数,但是当代码运行起来时还是同步执行,同一个调度任务还需要阻塞等待上一次任务执行完成之后才能继续执行下一次任务。不同调度任务也是同一样的,需要阻塞等待上一个调度任务完成之后,才可以继续执行下一个调度任务。所以我们需要开始定时器的多线程异步执行。

1.Java多线程方式

        通过在@Schedule注解方法,修改成异步执行,可以使用Java多线程

@SpringBootApplication
@Slf4j
@EnableScheduling
public class MyScheduledProgram {

    public static void main(String[] args) {
        SpringApplication.run(MyScheduledProgram.class, args);
    }

    /**
     * 每两秒执行一次
     */
    @Scheduled(fixedRate = 2000L)
    public void myScheduledGet() {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        executorService.submit(() -> {
            log.info("++++++++++++MyScheduledGet");
        });
    }

    ExecutorService executorServiceSet = Executors.newSingleThreadExecutor();

    /**
     * 每三秒执行一次
     *
     * @throws InterruptedException
     */
    @Scheduled(fixedRate = 3000L)
    public void myScheduledSet() {
        executorServiceSet.submit(() -> {
            int sleepTime = Double.valueOf(Math.random() * 10).intValue();
            log.info("==============MyScheduledSet; sleep time(second):{}", sleepTime);
            try {
                Thread.sleep(sleepTime * 1000);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        });

    }
}

 

 2.@EnableAsync和@Async

        对于同一个调度任务的执行,如果任务的执行时间超过该任务的下一次执行时间,会启动另外一个线程去执行,不会跳造成任务丢失(前提:有空闲线程去执行)
        对于多个不同的调度任务在执行时间上有交集,在执行任务A的过程中,到了任务B的执行时间,任务B不会阻塞,不需要等待任务A完成,会启动另外一个线程去执行任务B(前提:有空闲线程去执行)

@SpringBootApplication
@Slf4j
@EnableScheduling
@EnableAsync
public class MyScheduledProgram {

    public static void main(String[] args) {
        SpringApplication.run(MyScheduledProgram.class, args);
    }

    /**
     * 每两秒执行一次
     */
    @Scheduled(fixedRate = 2000L)
    @Async("taskAsyncScheduler")
    public void myScheduledGet() {
        log.info("++++++++++++MyScheduledGet");
    }


    /**
     * 每三秒执行一次
     *
     * @throws InterruptedException
     */
    @Scheduled(fixedRate = 3000L)
    // 指定值TaskScheduler使用默认
    @Async("taskAsyncScheduler")
    public void myScheduledSet() {
        int sleepTime = Double.valueOf(Math.random() * 10).intValue();
        log.info("==============MyScheduledSet; sleep time(second):{}", sleepTime);
        try {
            Thread.sleep(sleepTime * 1000);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

    }

    @Bean("taskAsyncScheduler")
    public TaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.setPoolSize(3);
        return taskScheduler;
    }
}

3.注入TaskScheduler定时任务线程池,增加线程个数

@SpringBootApplication
@Slf4j
@EnableScheduling
public class MyScheduledProgram {

    public static void main(String[] args) {
        SpringApplication.run(MyScheduledProgram.class, args);
    }

    /**
     * 每两秒执行一次
     */
    @Scheduled(fixedRate = 2000L)
    public void myScheduledGet() {
        log.info("++++++++++++MyScheduledGet");
    }


    /**
     * 每三秒执行一次
     *
     * @throws InterruptedException
     */
    @Scheduled(fixedRate = 3000L)
    public void myScheduledSet() {
        int sleepTime = Double.valueOf(Math.random() * 10).intValue();
        log.info("==============MyScheduledSet; sleep time(second):{}", sleepTime);
        try {
            Thread.sleep(sleepTime * 1000);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

    }

    @Bean
    public TaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.setPoolSize(3);
        return taskScheduler;
    }
}

 

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐