In the development, we sometimes encounter the demand of regular push, such as regular push, regular email and so on. SpringBoot has built-in timing tasks for us. We only need an annotation to enable timing for our use.
Start scheduled task
Add the @ enableshcheduling annotation in the entry class LogApplication. After adding the annotation, SpringBoot has determined that we need to use the scheduled task to complete some business logic. The corresponding configuration file will be added internally corresponding to the original configuration scheduled task.
@SpringBootApplication @EnableScheduling + // Enable scheduled tasks public class LogApplication {
@Scheduled
Configuring Scheduled tasks is very simple. You only need to add the @ Scheduled annotation to the methods that need to be executed regularly. Note that this class needs to be marked with component annotations, such as @ Componet, so that this class can be injected into the Spring container for management, which is used to indicate that this is a Bean managed by Spring, and @ Scheduled will take effect.
Of course, the derived annotation of @ component: @ Repository, @Service, @Controller will be used 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() { /** * Once per second */ logger.info("scheduler1 implement: " + System.currentTimeMillis()); }
Operation results:
2022-02-14 13:46:50.000 INFO 2337 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : scheduler1 implement: 1644828410000 2022-02-14 13:46:51.003 INFO 2337 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : scheduler1 implement: 1644828411003 2022-02-14 13:46:52.000 INFO 2337 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : scheduler1 implement: 1644828412000 2022-02-14 13:46:53.000 INFO 2337 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : scheduler1 implement: 1644828413000
You can see that the time interval between printing 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, which is a string, such asMeans every 5 seconds.
Zone: time zone. The default is the time zone where the server is located, and the receiving type is Java util. TimeZone.
fixedDelay: how long after the last execution is completed. For example:
@Scheduled(fixedDelay = 10000) //Execute 10 seconds after the last execution
fixedRate: indicates how long after the last execution starts. The usage is the same as above.
initialDelay: indicates how long the first task execution is delayed. The usage is the same as above.
@Scheduled thread issues
@Scheduled is executed by a single thread by default. 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, resulting in congestion.
For example, we give an example below: two unrelated scheduled tasks: printing log print and generating table generate need to be triggered once per second. If it takes 3 seconds to execute generate once, both print and generate can only be executed after the execution of generate this time, which will not achieve the effect of executing print and generate once a second.
Let's test it with code
We use thread Sleep () simulates the time taken to execute the method. Both are executed once per second, in which test1 sleeps for 3 seconds and the simulation takes time.
@Scheduled(cron = "* * * * * ?") public void test1() { /** * Once per second */ logger.info("test1 Execute and sleep for 3 seconds: " + System.currentTimeMillis()); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } logger.info("test1 end of execution: " + System.currentTimeMillis()); } @Scheduled(cron = "* * * * * ?") public void test2() { /** * Once per second */ logger.info("test2 implement: " + System.currentTimeMillis()); }
Operation results:
2022-02-14 14:09:41.004 INFO 2484 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : test1 Execute and sleep for 3 seconds: 1644829781004 2022-02-14 14:09:44.007 INFO 2484 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : test1 end of execution: 1644829784007 2022-02-14 14:09:44.010 INFO 2484 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : test2 implement: 1644829784010 2022-02-14 14:09:45.005 INFO 2484 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : test1 Execute and sleep for 3 seconds: 1644829785005 2022-02-14 14:09:48.007 INFO 2484 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : test1 end of execution: 1644829788007 2022-02-14 14:09:48.008 INFO 2484 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : test2 implement: 1644829788008 2022-02-14 14:09:49.009 INFO 2484 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : test2 implement: 1644829789009 2022-02-14 14:09:49.011 INFO 2484 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : test1 Execute and sleep for 3 seconds: 1644829789011 2022-02-14 14:09:52.012 INFO 2484 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : test1 end of execution: 1644829792012 2022-02-14 14:09:52.013 INFO 2484 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : test2 implement: 1644829792013 2022-02-14 14:09:53.005 INFO 2484 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : test1 Execute and sleep for 3 seconds: 1644829793005
It can be seen that the threads executing are all [scheduling-1], and the execution interval of test2 is not fixed, which is set to 1s, but sometimes 1s, sometimes 3s and 4s.
Then, how to make each scheduled task execute on time according to the configured timing rules? This requires us to configure timed tasks in a multi-threaded manner.
Executing methods asynchronously using @ Async
The same as adding scheduled tasks, @ EnableAsync is added to the entry class to enable asynchronous execution. Add @ Async annotation on the scheduled task to identify the asynchronous execution of the method. The method code is the same as above.
@Async + @Scheduled(cron = "* * * * * ?") public void test1() {
At this time, we will execute the code to see the effect:
2022-02-14 14:45:04.001 INFO 2608 --- [ task-4] club.yunzhi.log.task.DayLogTask : test1 Execute and sleep for 3 seconds: 1644831904001 2022-02-14 14:45:04.001 INFO 2608 --- [ task-1] club.yunzhi.log.task.DayLogTask : test1 end of execution: 1644831904001 2022-02-14 14:45:05.002 INFO 2608 --- [ task-2] club.yunzhi.log.task.DayLogTask : test1 end of execution: 1644831905002 2022-02-14 14:45:05.002 INFO 2608 --- [ task-5] club.yunzhi.log.task.DayLogTask : test1 Execute and sleep for 3 seconds: 1644831905002 2022-02-14 14:45:05.003 INFO 2608 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : test2 implement: 1644831905003 2022-02-14 14:45:06.001 INFO 2608 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : test2 implement: 1644831906001 2022-02-14 14:45:06.001 INFO 2608 --- [ task-6] club.yunzhi.log.task.DayLogTask : test1 Execute and sleep for 3 seconds: 1644831906001 2022-02-14 14:45:06.008 INFO 2608 --- [ task-3] club.yunzhi.log.task.DayLogTask : test1 end of execution: 1644831906008 2022-02-14 14:45:07.001 INFO 2608 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : test2 implement: 1644831907001 2022-02-14 14:45:07.001 INFO 2608 --- [ task-4] club.yunzhi.log.task.DayLogTask : test1 end of execution: 1644831907001 2022-02-14 14:45:07.002 INFO 2608 --- [ task-7] club.yunzhi.log.task.DayLogTask : test1 Execute and sleep for 3 seconds: 1644831907002
Although the method takes 3 seconds to execute, each task is triggered every second and executed on time. It can be seen from the previous thread number that different threads are used for task execution. test2 uses the thread number of scheduling-1, once per second. test1 asynchrony uses multiple thread numbers.
@The default number of Async thread pools is 8.
The default @ Async can cope with general scenarios, but there will be some risks if the concurrency is high. For example, excessive overhead, memory overflow, etc. To make the service run stably, we can customize and configure the thread pool, and then let the methods that need asynchronous execution specify to run with the thread pool.
For details, please refer to this article: https://www.interhorse.cn/a/3...
In the current project, the method of timed task execution is fast, and the interval is at the minute level, so multi-threaded timed task is not used.
The above is related to the scheduled task.