In development, sometimes there is a need for timing push, such as timing push, timing email, and so on. SpringBoot has built-in timing tasks for us, and we only need one annotation to turn on timing for our use.
Start scheduled tasks
Add the @EnableScheduling annotation to the entry class LogApplication. After adding the annotation, SpringBoot has determined that we want to use timed tasks to complete some business logic, and the corresponding configuration files will be added internally corresponding to the original configuration timed tasks.
@SpringBootApplication
@EnableScheduling + // 启用定时任务
public class LogApplication {
@Scheduled
Configuring a scheduled task is very simple, just add the annotation to the method that needs to be executed . Note , This class needs to be marked with component annotation , such as @Componet , so that this class will be injected into the Spring container for management, which is used to indicate that this is a Bean managed by Spring, will take effect.
Of course, the derived annotations of @Coponent are generally used: @Repository, @Service, @Controller instead, which will not be discussed here.
@Service +
public class DayLogTaskImpl implements DayLogTask {
@Scheduled(cron = "* * * * * ?") +
public void test1() {
Now let's test the code:
@Scheduled(cron = "* * * * * ?")
public void test1() {
/**
* 每秒执行一次
*/
logger.info("scheduler1 执行: " + System.currentTimeMillis());
}
operation result:
2022-02-14 13:46:50.000 INFO 2337 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : scheduler1 执行: 1644828410000
2022-02-14 13:46:51.003 INFO 2337 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : scheduler1 执行: 1644828411003
2022-02-14 13:46:52.000 INFO 2337 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : scheduler1 执行: 1644828412000
2022-02-14 13:46:53.000 INFO 2337 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : scheduler1 执行: 1644828413000
It can be seen that the printed time interval is about 1000 milliseconds, which is executed once per second according to the definition.
@Scheduled annotation parameter description
cron : This parameter receives a cron expression, the cron expression is a string, such as means to execute every 5 seconds.
zone: The time zone. The default is the time zone where the server is located, and the receiving type is java.util.TimeZone.
fixedDelay: How long to execute after the last execution time point. like:
@Scheduled(fixedDelay = 10000) //上一次执行完毕时间点之后10秒再执行
fixedRate: Indicates how long after the last execution to start again. The usage is the same as above.
initialDelay: Indicates how long to delay the first task execution. The usage is the same as above.
Threading issue with @Scheduled
@Scheduled is single-threaded by default, and multiple @Scheduled tasks use the same thread. If a task is a time-consuming operation, other scheduled tasks will wait for the execution of the task to complete, causing blockage.
For example, we give an example below: two unrelated timing tasks: print log print and generate table generate , both of which need to be triggered every second. If the Generate perform a time-consuming need 3 seconds, Print and the Generate have to wait this time the Generate after the implementation of longer execution, not up to the task which Print, the Generate executed every second effect.
Let's test it with code
We use Thread.sleep() to simulate the time-consuming execution of the method. Both are executed every second, where test1 sleeps for 3 seconds and the simulation takes time.
@Scheduled(cron = "* * * * * ?")
public void test1() {
/**
* 每秒执行一次
*/
logger.info("test1执行并睡眠3秒: " + System.currentTimeMillis());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
logger.info("test1执行结束: " + System.currentTimeMillis());
}
@Scheduled(cron = "* * * * * ?")
public void test2() {
/**
* 每秒执行一次
*/
logger.info("test2 执行: " + System.currentTimeMillis());
}
operation result:
2022-02-14 14:09:41.004 INFO 2484 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : test1执行并睡眠3秒: 1644829781004
2022-02-14 14:09:44.007 INFO 2484 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : test1执行结束: 1644829784007
2022-02-14 14:09:44.010 INFO 2484 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : test2 执行: 1644829784010
2022-02-14 14:09:45.005 INFO 2484 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : test1执行并睡眠3秒: 1644829785005
2022-02-14 14:09:48.007 INFO 2484 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : test1执行结束: 1644829788007
2022-02-14 14:09:48.008 INFO 2484 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : test2 执行: 1644829788008
2022-02-14 14:09:49.009 INFO 2484 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : test2 执行: 1644829789009
2022-02-14 14:09:49.011 INFO 2484 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : test1执行并睡眠3秒: 1644829789011
2022-02-14 14:09:52.012 INFO 2484 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : test1执行结束: 1644829792012
2022-02-14 14:09:52.013 INFO 2484 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : test2 执行: 1644829792013
2022-02-14 14:09:53.005 INFO 2484 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : test1执行并睡眠3秒: 1644829793005
It can be seen that the execution threads are all [scheduling-1], and the execution interval of test2 is not fixed at 1s, but sometimes is 1s, sometimes 3s, 4s.
So, how can each scheduled task be executed on time according to the configured timing rules? This requires us to configure the timing task into a multi-threaded way.
Execute methods asynchronously with @Async
Same as adding timed tasks, add @EnableAsync to the entry class to enable asynchronous execution. Add the @Async annotation to the scheduled task to indicate that the method is executed asynchronously. The method code is the same as above.
@Async +
@Scheduled(cron = "* * * * * ?")
public void test1() {
At this time, let's execute the code to see the effect:
2022-02-14 14:45:04.001 INFO 2608 --- [ task-4] club.yunzhi.log.task.DayLogTask : test1执行并睡眠3秒: 1644831904001
2022-02-14 14:45:04.001 INFO 2608 --- [ task-1] club.yunzhi.log.task.DayLogTask : test1执行结束: 1644831904001
2022-02-14 14:45:05.002 INFO 2608 --- [ task-2] club.yunzhi.log.task.DayLogTask : test1执行结束: 1644831905002
2022-02-14 14:45:05.002 INFO 2608 --- [ task-5] club.yunzhi.log.task.DayLogTask : test1执行并睡眠3秒: 1644831905002
2022-02-14 14:45:05.003 INFO 2608 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : test2 执行: 1644831905003
2022-02-14 14:45:06.001 INFO 2608 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : test2 执行: 1644831906001
2022-02-14 14:45:06.001 INFO 2608 --- [ task-6] club.yunzhi.log.task.DayLogTask : test1执行并睡眠3秒: 1644831906001
2022-02-14 14:45:06.008 INFO 2608 --- [ task-3] club.yunzhi.log.task.DayLogTask : test1执行结束: 1644831906008
2022-02-14 14:45:07.001 INFO 2608 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : test2 执行: 1644831907001
2022-02-14 14:45:07.001 INFO 2608 --- [ task-4] club.yunzhi.log.task.DayLogTask : test1执行结束: 1644831907001
2022-02-14 14:45:07.002 INFO 2608 --- [ task-7] club.yunzhi.log.task.DayLogTask : test1执行并睡眠3秒: 1644831907002
Although it takes 3 seconds to execute the method, each task of is executed on time according to the trigger once per second. It can be seen from the previous thread number that the execution of the task uses a different thread . Test2 uses the thread number of scheduling-1, once per second. Test1 asynchronously uses multiple thread numbers.
@Async The default number of thread pools is 8 .
The default @Async can cope with general scenarios, but if the concurrency is relatively high, there will be certain risks. For example, excessive overhead, memory overflow, etc. In order to make the service run stably, we can customize the configuration thread pool, and then let the method that needs to be executed asynchronously specify the thread pool to run.
Simply put, it is to configure an Executor, configure the number of core threads, the maximum number of threads, the queue size and other information. Specify the thread pool to call with @Async("myExecutor").
@Configuration
public class ExecutorConfig {
@Bean(name = "myExecutor")
public Executor taskExecutor() {
For details, please refer to this article: https://www.interhorse.cn/a/3350135757/
In the current project, the method of executing timed tasks is faster, and the interval is at the minute level, so multi-threaded timed tasks are not used. Record them to prevent future needs.
The above is the related content of timed tasks.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。