3

We often encounter such scenarios when writing Spring Boot applications. For example, I need to periodically send some short messages, emails and other operations, and may also periodically check and monitor some signs, parameters, etc.

Create a scheduled task

Writing a timed task in Spring Boot is very simple. The following example introduces how to create a timed task in Spring Boot to output the current time every 5 seconds.

  • @EnableScheduling annotation to the main class of Spring Boot to enable the configuration of timing tasks
@SpringBootApplication
@EnableScheduling
public class Application {

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

}
  • Create a timer task implementation class
@Component
public class ScheduledTasks {

    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");

    @Scheduled(fixedRate = 5000)
    public void reportCurrentTime() {
        log.info("现在时间:" + dateFormat.format(new Date()));
    }

}
  • Run the program, you can see output similar to the following in the console, and the timing task starts to operate normally.
2021-07-13 14:56:56.413  INFO 34836 --- [           main] c.d.chapter71.Chapter71Application       : Started Chapter71Application in 1.457 seconds (JVM running for 1.835)
2021-07-13 14:57:01.411  INFO 34836 --- [   scheduling-1] com.didispace.chapter71.ScheduledTasks   : 现在时间:14:57:01
2021-07-13 14:57:06.412  INFO 34836 --- [   scheduling-1] com.didispace.chapter71.ScheduledTasks   : 现在时间:14:57:06
2021-07-13 14:57:11.413  INFO 34836 --- [   scheduling-1] com.didispace.chapter71.ScheduledTasks   : 现在时间:14:57:11
2021-07-13 14:57:16.413  INFO 34836 --- [   scheduling-1] com.didispace.chapter71.ScheduledTasks   : 现在时间:14:57:16

@Scheduled detailed explanation

In the introductory example above, the @Scheduled(fixedRate = 5000) annotation is used to define the task to be executed every 5 seconds. For @Scheduled , let's see what configurations are available from the source code:

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(Schedules.class)
public @interface Scheduled {

    String CRON_DISABLED = ScheduledTaskRegistrar.CRON_DISABLED;

    String cron() default "";

    String zone() default "";

    long fixedDelay() default -1;

    String fixedDelayString() default "";

    long fixedRate() default -1;

    String fixedRateString() default "";

    long initialDelay() default -1;

    String initialDelayString() default "";

}

The meaning of these specific configuration information is as follows:

  • cron: configure execution rules through cron expressions
  • zone: the time zone used in cron expression parsing
  • fixedDelay: the interval between the end of the previous execution and the beginning of the next execution (unit: ms)
  • fixedDelayString: the interval between the end of the last task execution and the start of the next execution, using java.time.Duration#parse to parse
  • fixedRate: execute the task at a fixed interval, that is, the interval time (unit: ms) from the start of the last task execution to the start of the next execution. If the task is scheduled to be executed, the last task has not been executed yet, it will be added to the worker queue and wait for it. Execute the next task immediately after the completion of one execution
  • fixedRateString: Consistent with fixedRate logic, just use java.time.Duration#parse to parse
  • initialDelay: the delay time for the first task execution
  • initialDelayString: the delay time of the first task execution, use java.time.Duration#parse to parse

Thinking and advancement

Is it easy to implement timing tasks like this? So continue to think about whether there are any disadvantages in this way of implementation?

It may not be easy for beginners to find the problem, but if you already have some online project experience, the problem is also obvious: the timing tasks implemented by this mode lack a coordination mechanism in the cluster environment.

What does that mean? Suppose, we want to implement a timed task, which is used to count a certain data online every day and then add it to the original data. There will be no problems when we develop and test, because they are all running in a single process. However, when we deploy such timing tasks to the production environment, for higher availability, it is necessary to start multiple instances. At this point, as soon as the time is up, all the started instances will start executing this task at the same time. Then the problem also arises, because of the accumulation operation, eventually our results will have problems.

There are many ways to solve this problem. The more common one is to use distributed locks to control the execution order of similar tasks before using distributed locks. For example, use Redis, Zookeeper and other intermediates with distributed lock functions. The cooperation of software can help us to coordinate the execution rules of this kind of task in the cluster mode.

Apart from this, do you have any good way to solve it? Leave a comment and tell us your opinion! Don't go away, this series of tutorial "Spring Boot 2.x Basic Tutorial" is continuously updated! . If you encounter difficulties in the learning process, it is recommended to join Spring Technical Exchange Group , participate in exchanges and discussions, and better study and progress!

Code example

The complete project of this article can be viewed in the chapter7-1 directory in the following warehouse:

**If you think this article is good, welcome Star support, your attention is my motivation for persistence!

Welcome to pay attention to my public account: Program Ape DD, share knowledge and thoughts that can’t be seen elsewhere

程序猿DD
2.2k 声望2.8k 粉丝

作品:《Spring Cloud微服务实战》、SpringForAll社区、OpenWrite、Youtube中文配音