java小白的成长记录之定时任务实践

1,197 阅读4分钟

一、背景

再次进行java小白的学习成长喽。

平时的日常工作主要就是接口+脚本,那么问题来了,java是如何将定时任务跑起来的。

查找资料了解到java本身有一套类似于linux的crontab的功能,并且还支持秒级控制。crontab只支持到分钟,之前php脚本只能用while(true)+sleep()的方式实现。

好,进入今天的实践吧~

二、导入核心包

在pom.xml将加入下面内容

    <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

三、开启定时任务的配置

程序的总入口DemoApplication,增加@EnableScheduling注解,开启定时任务的配置

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling  
public class DemoApplication {

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

}

四、定时脚本处理

新建CronTab.java,代码如下:

package com.example.demo.controller;


import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component
public class CronTab {
    private static Logger logger = LoggerFactory.getLogger(CronTab.class);
    
    @Scheduled(cron = "0/5 * * * * *")
    public void testLog() {
        logger.info("===testLog开启===" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        try {
            Thread.sleep(6000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        logger.info("===testLog结束===" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
    }
}

打印日志:

2020-05-31 19:41:45.000  INFO 500 --- [taskScheduler-1] com.example.demo.controller.CronTab      : ===testLog开启===2020-05-31 19:41:45
2020-05-31 19:41:51.001  INFO 500 --- [taskScheduler-1] com.example.demo.controller.CronTab      : ===testLog结束===2020-05-31 19:41:51
2020-05-31 19:41:51.001  INFO 500 --- [taskScheduler-1] com.example.demo.controller.CronTab      : ===testLog开启===2020-05-31 19:41:51
2020-05-31 19:41:57.002  INFO 500 --- [taskScheduler-1] com.example.demo.controller.CronTab      : ===testLog结束===2020-05-31 19:41:57
2020-05-31 19:41:57.002  INFO 500 --- [taskScheduler-1] com.example.demo.controller.CronTab      : ===testLog开启===2020-05-31 19:41:57

嗯,看着还挺符合预期的,每隔5s运行一次。

但是把testLog复制了几次,多加了几个定时任务:

emmm 执行的很有序,一个完成另外一个在开始,但是很明显,这不是我们想要的...

原因是定时任务默认都是使用单线程执行的。

那么接下来我们开始搞多进程处理定时任务

五、开启多进程

增加CronConfig.java

package com.example.demo.controller;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;

@Configuration
public class CronConfig {
    @Bean
    public TaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        // 设置scheduler执行线程为3个
        scheduler.setPoolSize(3);
        return scheduler;
    }
}

再来看下效果:

嗯,看起来很完美。那我接着把定时任务设置的凌乱点,有的5s执行一次,有的3s执行一次,再来看下效果:

emmmm 经过初次实践,将进程数设置多点和时间凌乱点都会导致不太理想,这个还需继续查询一下应该如何处理,挖个坑待填上吧(ps:这个多进程的方案是从网上找的,不确定是不是我哪里写的有问题)

六、定时时间配置

关于定时时间的设置方式如下:

这四种的具体说明:

1、@Scheduled(fixedDelay = 1000)

fixedDelay控制方法执行的间隔时间,是以上一次方法执行完开始算起,如上一次方法执行阻塞住了,那么直到上一次执行完,并间隔给定的时间后,执行下一次。

2、@Scheduled(fixedRate = 5000)

fixedRate是按照一定的速率执行,是从上一次方法执行开始的时间算起,如果上一次方法阻塞住了,下一次也是不会执行,但是在阻塞这段时间内累计应该执行的次数,当不再阻塞时,一下子把这些全部执行掉,而后再按照固定速率继续执行。

3、@Scheduled(cron="0/5 * * * * ? ")

cron表达式可以定制化执行任务,但是执行的方式是与fixedDelay相近的,也是会按照上一次方法结束时间开始算起。

CronTrigger配置完整格式为: [秒] [分] [小时] [日] [月] [周] [年]

4、@Scheduled(initialDelay = 50000,fixedRate = 6000)

这个定时器就是在fixedRate的基础上加了一个initialDelay = 10000 意思就是在容器启动后,延迟10秒后再执行一次定时器,以后每15秒再执行一次该定时器。

七、后记

哈,还有多进程的问题没完全解决,并没有到写后记的时候,待我填坑完成再补写后记吧

成长记录传送门:

输出hello word!

curl的实现

JdbcTemplate实践