Scheduled注解使用

1、Scheduled注解用于执行定时任务,参数有以下几种:
cron(自定义格式)
fixedDelay(上次任务执行结束时间点延迟多久)
fixedRate(如果任务执行时间小于rate,那么两次任务的开始时间间隔rate执行,如果大于rate,那么上次任务执行完立即执行)
这三种设置间隔的方式只能使用其中一种,不能同时存在。
使用注解时,同时要使用@EnableScheduling注解,开启scheduled,不然不会执行

2、没有设置异步执行的情况下,不管多少个定时任务,都是 使用同一个线程执行
测试代码:

@Component
@Lazy(false)
//@EnableAsync
public class DataClearTask {

	@Scheduled(cron = "0/5 * *  * * ?")
//	@Async("taskPoolExecutor")
	public void cleanTaskData() throws InterruptedException {
		System.out.println("clean:"+new Date().getTime() + ":" +Thread.currentThread().getName());
		Thread.sleep(10000);
		System.out.println("clean:"+new Date().getTime() + ":" +Thread.currentThread().getName()+":task end");
	}
	@Scheduled(cron = "0/5 * *  * * ?")
//	@Async("taskPoolExecutor")
	public void washTaskData() throws InterruptedException {
		System.out.println("wash:"+new Date().getTime() + ":" +Thread.currentThread().getName());
		Thread.sleep(10000);
		System.out.println("wash:"+new Date().getTime() + ":" +Thread.currentThread().getName()+":task end");
	}
}

执行结果:

clean:1535453165007:pool-5-thread-1
clean:1535453175008:pool-5-thread-1:task end
wash:1535453175008:pool-5-thread-1
wash:1535453185009:pool-5-thread-1:task end
clean:1535453185009:pool-5-thread-1
clean:1535453195010:pool-5-thread-1:task end
wash:1535453195010:pool-5-thread-1
wash:1535453205011:pool-5-thread-1:task end
clean:1535453205011:pool-5-thread-1
clean:1535453215012:pool-5-thread-1:task end
wash:1535453215012:pool-5-thread-1

3、使用异步线程
先定义一个线程池

@Bean(name = "taskPoolExecutor")
    public ExecutorService taskPoolExecutor() {
        ExecutorService poolExecutor = new ThreadPoolExecutor(threadCoreSize, threadMaxSize, 60L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue(queueSize), new ThreadPoolExecutor.CallerRunsPolicy());
        return poolExecutor;
    }

scheduled使用,使用@Async注解时,要同时使用@EnableAsync,不然异步执行不生效

@Component
@Lazy(false)
@EnableAsync
public class DataClearTask {

	@Scheduled("0/5 * *  * * ?")
	@Async("taskPoolExecutor")
	public void cleanTaskData() throws InterruptedException {
		System.out.println(new Date().getTime() + ":" +Thread.currentThread().getName());
		Thread.sleep(10000);
		System.out.println(new Date().getTime() + ":" +Thread.currentThread().getName()+":task end");
	}
}

执行结果:

1535450825001:pool-3-thread-4
1535450830002:pool-3-thread-5
1535450830002:pool-3-thread-3:task end
1535450835001:pool-3-thread-4:task end
1535450835001:pool-3-thread-1
1535450840000:pool-3-thread-2
1535450840002:pool-3-thread-5:task end
1535450845001:pool-3-thread-1:task end
1535450845001:pool-3-thread-3
1535450850000:pool-3-thread-2:task end
1535450850000:pool-3-thread-4
1535450855001:pool-3-thread-3:task end
1535450855001:pool-3-thread-5
1535450860000:pool-3-thread-4:task end
1535450860001:pool-3-thread-1
1535450865001:pool-3-thread-5:task end
1535450865001:pool-3-thread-2
1535450870001:pool-3-thread-1:task end
1535450870001:pool-3-thread-1
1535450875001:pool-3-thread-2:task end
1535450875001:pool-3-thread-4
1535450880001:pool-3-thread-1:task end
1535450880001:pool-3-thread-5
1535450885001:pool-3-thread-4:task end

4、使用异步线程,相当于任务执行方法在异步线程中执行,所以执行会有个问题,如果执行时间超过定义的时间间隔,那么多线程执行可能会重复执行到一部分任务

20180906更新

另外还有一种设置线程池的方式,创建一个被ScheduledAnnotationBeanPostProcessor加载的类,具体参考:https://blog.csdn.net/a718515028/article/details/80396102

@Configuration
public class TestConfiguration implements SchedulingConfigurer {

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setScheduler(TaskScheduler());
    }
    @Bean(destroyMethod = "shutdown")
    public Executor TaskScheduler() {
        return Executors.newScheduledThreadPool(10);
    }
}

测试结果(测试代码重新写的,所以日志和上文不一样)

2018-09-06 11:51:20,001 [pool-3-thread-1] INFO  [com.zhongan.thanos.task.testTask] [testTask.java:26] - test1:1536205880001:start:pool-3-thread-1 [] 
2018-09-06 11:51:20,002 [pool-3-thread-1] INFO  [com.zhongan.thanos.task.testTask] [testTask.java:27] - test1:1536205880002:end:pool-3-thread-1 [] 
2018-09-06 11:51:25,001 [pool-3-thread-3] INFO  [com.zhongan.thanos.task.testTask] [testTask.java:26] - test1:1536205885001:start:pool-3-thread-3 [] 
2018-09-06 11:51:25,002 [pool-3-thread-3] INFO  [com.zhongan.thanos.task.testTask] [testTask.java:27] - test1:1536205885002:end:pool-3-thread-3 [] 
2018-09-06 11:51:30,000 [pool-3-thread-2] INFO  [com.zhongan.thanos.task.testTask] [testTask.java:26] - test1:1536205890000:start:pool-3-thread-2 [] 
2018-09-06 11:51:30,000 [pool-3-thread-2] INFO  [com.zhongan.thanos.task.testTask] [testTask.java:27] - test1:1536205890000:end:pool-3-thread-2 [] 
2018-09-06 11:51:35,001 [pool-3-thread-5] INFO  [com.zhongan.thanos.task.testTask] [testTask.java:26] - test1:1536205895001:start:pool-3-thread-5 [] 
2018-09-06 11:51:35,001 [pool-3-thread-5] INFO  [com.zhongan.thanos.task.testTask] [testTask.java:27] - test1:1536205895001:end:pool-3-thread-5 [] 
2018-09-06 11:51:40,001 [pool-3-thread-3] INFO  [com.zhongan.thanos.task.testTask] [testTask.java:26] - test1:1536205900001:start:pool-3-thread-3 [] 

这种方法多次执行也是使用的不同线程,但是和第一种方法有些差别。
第一种方法是纯异步,每个任务都是不同的线程,且如果我们在某一任务方法中打了断点或者执行时间过长,那么会有其他线程重新执行这个任务,所以会有上文说的重复执行的问题。所以各个任务+各个频次都是异步的。

第二种方法可以说是半异步,不同的任务是不同线程执行,同一个任务上一次执行完,下一次线程可能不一样,但是和第一种方法的区别是,如果任务方法中打了断点或者时间过长,那么不会有新的线程执行这个任务。所以这种方法各个任务是异步的,但是同一任务的各个频次之间是串行同步的,不会有上文说的重复执行的问题

你可能感兴趣的:(spring)