• 欢迎光临~

@Schedule执行定时任务

开发技术 开发技术 2022-07-25 次浏览

@Shcedule默认情况下会单线程顺序执行。如果一个定时任务执行时间大于其任务间隔时间,那么下一次将会等待上一次执行结束后再继续执行。如果多个定时任务在同一时刻执行,任务会依次执行。

1. 单线程顺序执行demo:

 

package com.citi.ark.mls.timer;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

@Service
@Slf4j
//@EnableAsync

public class ExecuteSequence {
    @Scheduled(cron = "0/3 * * * * ?")
//    @Async
    public void test1() throws InterruptedException {
        Long current=System.currentTimeMillis();
        log.info("===this is test1 start:{}===",current);
        Thread.sleep(9900);
        log.info("===this is test1 end:{}===",System.currentTimeMillis()-current);
//        log.info("==test1 output:{}",i++);
    }

    @Scheduled(cron = "0/3 * * * * ?")
//    @Async
    public void test2() throws InterruptedException {
        Long current=System.currentTimeMillis();
        log.info("===this is test2 start:{}===",current);
        Thread.sleep(5000);
        log.info("===this is test2 end:{}===",System.currentTimeMillis()-current);
//        log.info("==test2 output:{}",i++);
    }

    private Integer getResult(int i){
        int j=i++;
        return j;
    }
}

 

执行结果如下,可见是单线程顺序执行

2022-07-22 18:08:27.013 c.c.a.m.t.ExecuteSequence scheduling-1 [INFO] ===this is test1 start:1658484507013===
2022-07-22 18:08:37.027 c.c.a.m.t.ExecuteSequence scheduling-1 [INFO] ===this is test1 end:10014===
2022-07-22 18:08:37.029 c.c.a.m.t.ExecuteSequence scheduling-1 [INFO] ===this is test2 start:1658484517028===
2022-07-22 18:08:42.037 c.c.a.m.t.ExecuteSequence scheduling-1 [INFO] ===this is test2 end:5009===
2022-07-22 18:08:42.039 c.c.a.m.t.ExecuteSequence scheduling-1 [INFO] ===this is test1 start:1658484522038===
2022-07-22 18:08:52.041 c.c.a.m.t.ExecuteSequence scheduling-1 [INFO] ===this is test1 end:10003===

 

2. 异步方式处理——利用Spring提供的@Async注解和@EnableAsync注解

demo 1 中效率会比较低

package mls.timer;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

@Service
@Slf4j
@EnableAsync
public class ExecuteSequence {
@Scheduled(cron = "0/3 * * * * ?")
@Async
public void test1() throws InterruptedException {
Long current=System.currentTimeMillis();
log.info("===this is test1 start:{}===",current);
Thread.sleep(10000);
log.info("===this is test1 end:{}===",System.currentTimeMillis()-current);
// log.info("==test1 output:{}",i++);
}

@Scheduled(cron = "0/3 * * * * ?")
@Async
public void test2() throws InterruptedException {
Long current=System.currentTimeMillis();
log.info("===this is test2 start:{}===",current);
Thread.sleep(5000);
log.info("===this is test2 end:{}===",System.currentTimeMillis()-current);
// log.info("==test2 output:{}",i++);
}

private Integer getResult(int i){
int j=i++;
return j;
}
}
执行结果如下,由于test1/test2执行时间是5s>任务调度周期3s,发生上一个任务未执行完毕下一个任务又开始执行逻辑,从如下执行结果可以明显可出。所以最好执行方式是采用多线程自己控制线程数据量

2022-07-25 11:38:18.030 c.c.a.m.t.ExecuteSequence task-1 [INFO] ===this is test2 start:1658720298030===
2022-07-25 11:38:18.030 c.c.a.m.t.ExecuteSequence task-2 [INFO] ===this is test1 start:1658720298030===  //
2022-07-25 11:38:21.007 c.c.a.m.t.ExecuteSequence task-3 [INFO] ===this is test1 start:1658720301007===  //上一个test1还没end下一个test1又开始了
2022-07-25 11:38:21.007 c.c.a.m.t.ExecuteSequence task-4 [INFO] ===this is test2 start:1658720301007===
2022-07-25 11:38:23.036 c.c.a.m.t.ExecuteSequence task-1 [INFO] ===this is test2 end:5006===
2022-07-25 11:38:24.015 c.c.a.m.t.ExecuteSequence task-5 [INFO] ===this is test2 start:1658720304015===
2022-07-25 11:38:24.016 c.c.a.m.t.ExecuteSequence task-6 [INFO] ===this is test1 start:1658720304016===
2022-07-25 11:38:26.021 c.c.a.m.t.ExecuteSequence task-4 [INFO] ===this is test2 end:5014===
2022-07-25 11:38:27.002 c.c.a.m.t.ExecuteSequence task-7 [INFO] ===this is test2 start:1658720307002===
2022-07-25 11:38:27.003 c.c.a.m.t.ExecuteSequence task-8 [INFO] ===this is test1 start:1658720307003===
2022-07-25 11:38:28.037 c.c.a.m.t.ExecuteSequence task-2 [INFO] ===this is test1 end:10007===
2022-07-25 11:38:29.025 c.c.a.m.t.ExecuteSequence task-5 [INFO] ===this is test2 end:5010===
2022-07-25 11:38:30.011 c.c.a.m.t.ExecuteSequence task-1 [INFO] ===this is test1 start:1658720310011===
2022-07-25 11:38:30.011 c.c.a.m.t.ExecuteSequence task-4 [INFO] ===this is test2 start:1658720310011===
2022-07-25 11:38:31.012 c.c.a.m.t.ExecuteSequence task-3 [INFO] ===this is test1 end:10005===
2022-07-25 11:38:32.013 c.c.a.m.t.ExecuteSequence task-7 [INFO] ===this is test2 end:5011===
2022-07-25 11:38:33.003 c.c.a.m.t.ExecuteSequence task-2 [INFO] ===this is test1 start:1658720313003===
2022-07-25 11:38:33.003 c.c.a.m.t.ExecuteSequence task-5 [INFO] ===this is test2 start:1658720313003===
2022-07-25 11:38:34.025 c.c.a.m.t.ExecuteSequence task-6 [INFO] ===this is test1 end:10009===
2022-07-25 11:38:35.015 c.c.a.m.t.ExecuteSequence task-4 [INFO] ===this is test2 end:5004===
2022-07-25 11:38:36.012 c.c.a.m.t.ExecuteSequence task-3 [INFO] ===this is test1 start:1658720316012===
2022-07-25 11:38:36.012 c.c.a.m.t.ExecuteSequence task-7 [INFO] ===this is test2 start:1658720316012===
2022-07-25 11:38:37.008 c.c.a.m.t.ExecuteSequence task-8 [INFO] ===this is test1 end:10005===

 

3. 多线程执行  -- 自定义线程池 @EnableScheduling

demo2采用@Async 和@EnableAsync方式,每次定时任务启动都会创建一个单独的线程来处理,也就是说同一个定时任务(比如下例中test1)也会启动多个线程处理

首先需要实现SchedulingConfigurer接口,然后自定义线程池,这样凡是用到@Scheduled注解的都可以用该线程池
package com.citi.ark.mls.timer;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;

import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

@Configuration
@EnableScheduling
public class ScheduleConfig implements SchedulingConfigurer{
@Bean
public Executor executors() {
return Executors.newScheduledThreadPool(5,(Runnable r) ->{
Thread thread=new Thread(r);
thread.setName("ScheduleThread");
return thread;
});
}

@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
scheduledTaskRegistrar.setScheduler(executors());
}
}
package com.citi.ark.mls.timer;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

@Service
@Slf4j
public class ExecuteSequence {
@Scheduled(cron = "0/3 * * * * ?")
@Async
public void test1() throws InterruptedException {
Long current=System.currentTimeMillis();
log.info("===this is test1 start:{}===",current);
Thread.sleep(10000);
log.info("===this is test1 end:{}===",System.currentTimeMillis()-current);
// log.info("==test1 output:{}",i++);
}

@Scheduled(cron = "0/3 * * * * ?")
@Async
public void test2() throws InterruptedException {
Long current=System.currentTimeMillis();
log.info("===this is test2 start:{}===",current);
Thread.sleep(5000);
log.info("===this is test2 end:{}===",System.currentTimeMillis()-current);
// log.info("==test2 output:{}",i++);
}

private Integer getResult(int i){
int j=i++;
return j;
}
}

执行结果如下,可以看到test2在thread3未执行完之前并不会执行下一个test2任务,即解决了同一个任务启动多个线程处理问题

2022-07-25 11:32:48.008 c.c.a.m.t.ExecuteSequence Thread-3 [INFO] ===this is test2 start:1658719968008===
2022-07-25 11:32:48.008 c.c.a.m.t.ExecuteSequence Thread-4 [INFO] ===this is test1 start:1658719968008===
2022-07-25 11:32:53.010 c.c.a.m.t.ExecuteSequence Thread-3 [INFO] ===this is test2 end:5002===
2022-07-25 11:32:54.006 c.c.a.m.t.ExecuteSequence Thread-3 [INFO] ===this is test2 start:1658719974006===
2022-07-25 11:32:58.016 c.c.a.m.t.ExecuteSequence Thread-4 [INFO] ===this is test1 end:10008===
2022-07-25 11:32:59.019 c.c.a.m.t.ExecuteSequence Thread-3 [INFO] ===this is test2 end:5013===
2022-07-25 11:33:00.000 c.c.a.m.t.ExecuteSequence Thread-4 [INFO] ===this is test1 start:1658719980000===
2022-07-25 11:33:00.016 c.c.a.m.t.ExecuteSequence Thread-6 [INFO] ===this is test2 start:1658719980016===
2022-07-25 11:33:05.029 c.c.a.m.t.ExecuteSequence Thread-6 [INFO] ===this is test2 end:5013===
2022-07-25 11:33:06.012 c.c.a.m.t.ExecuteSequence Thread-6 [INFO] ===this is test2 start:1658719986012===
2022-07-25 11:33:10.015 c.c.a.m.t.ExecuteSequence Thread-4 [INFO] ===this is test1 end:10015===
2022-07-25 11:33:11.020 c.c.a.m.t.ExecuteSequence Thread-6 [INFO] ===this is test2 end:5008===
2022-07-25 11:33:12.007 c.c.a.m.t.ExecuteSequence Thread-4 [INFO] ===this is test1 start:1658719992007===
2022-07-25 11:33:12.007 c.c.a.m.t.ExecuteSequence Thread-5 [INFO] ===this is test2 start:1658719992007===
2022-07-25 11:33:17.012 c.c.a.m.t.ExecuteSequence Thread-5 [INFO] ===this is test2 end:5004===
2022-07-25 11:33:18.002 c.c.a.m.t.ExecuteSequence Thread-5 [INFO] ===this is test2 start:1658719998002===
2022-07-25 11:33:22.022 c.c.a.m.t.ExecuteSequence Thread-4 [INFO] ===this is test1 end:10015===
2022-07-25 11:33:23.011 c.c.a.m.t.ExecuteSequence Thread-5 [INFO] ===this is test2 end:5009===

 

参考:

https://www.jb51.net/article/226985.htm

https://blog.csdn.net/weixin_44117767/article/details/119996464

程序员灯塔
转载请注明原文链接:@Schedule执行定时任务
喜欢 (0)