Spring定时任务

通过类上设置注解@EnableScheduling可以开启spring自带的定时任务,@Scheduled设置定时时间。还可以通过ThreadPoolTaskSchedulerschedule(Runable,cron)动态添加

使用

@Component
@EnableScheduling //定时任务
public class SchedulingTest{
     //每30秒执行一次
    @Scheduled(fixedRate = 1000 * 30)
    public void doSomeThing(){
           //没30秒输出一次
           System.out.println ("定时输出:" + dateFormat ().format (new Date ()));
    }

    //在固定时间执行(当时间匹配规则时输出)
    @Scheduled(cron = "0 */1 *  * * * ")
    public void reportCurrentByCron(){
        System.out.println ("固定时间输出" + dateFormat ().format (new Date()));
    }

     private SimpleDateFormat dateFormat(){
        return new SimpleDateFormat ("HH:mm:ss");
    }
}

固定时间匹配规则

字段 允许值 允许的特殊字符
0-59 , - * /
0-59 , - * /
小时 0-23 , - * /
日期 1-31 , - * ? / L W C
月份 1-12 或者 JAN-DEC , - * /
星期 1-7 或者 SUN-SAT , - * ? / L C #
空, 1970-2099 , - * /
  • 每个元素都可以是一个值如6,一个区间9-12 一个间隔时间8-18/4 /4代表间隔四个小时,一个列表1,3,5
  • 日期和星期互斥,即两个元素重合,必须其中一个设置?忽略
  • *代表所有可能的值
  • /指定数值的增量,如0/10(分钟单位中)代表0分钟开始,10分钟执行一次
  • ?仅在日期和星期中,代表不指定值
  • L用于日期和星期中,代表倒数第几个
  • W仅在日其中,代表平日(工作日)。15W代表离15号最近的一个工作日。
  • C日期,5C五个单位后的第一天
  • #每个月第几个星期几,例如在4#2表示某月的第二个星期三。

转换异步线程

单线程执行时间超过定时间隔可能会出现任务丢失的情况,可以使用异步线程避免这个问题。

  • 配置Spring@EnableAsync
  • 执行方法上配置任务线程池@Async
//每30秒执行一次
   @Async("taskExecutor")
   @Scheduled(fixedRate = 1000 * 3)
    public void xxx(){
        //...
    }

分布式情况下避免重复执行

  1. lock = redisTemplate.opsForValue().setIfAbsent(KEY, LOCK);采用Redis判断是否存在key,不存在则设置key,执行完成删除key的方式加锁(跨时区部署还是会重复执行)
  2. shedlock加锁
        
            net.javacrumbs.shedlock
            shedlock-spring
            0.16.1
        

        
            net.javacrumbs.shedlock
            shedlock-provider-jdbc-template
            0.16.1
        

配置(jdbc),还有redis,mongo,zookeeper等锁的实现

@Configuration
@EnableScheduling
public class ShedlockConfig {

    @Bean
    public LockProvider lockProvider(DataSource dataSource) {
        return new JdbcTemplateLockProvider(dataSource);
    }

    @Bean
    public ScheduledLockConfiguration scheduledLockConfiguration(LockProvider lockProvider) {
        return ScheduledLockConfigurationBuilder
                .withLockProvider(lockProvider)
                .withPoolSize(10)
                .withDefaultLockAtMostFor(Duration.ofMinutes(10))//lock expire最大时间10分钟
                .build();
    }
}

shedlock表

CREATE TABLE shedlock(
    name VARCHAR(64),
    lock_until TIMESTAMP(3) NULL,
    locked_at TIMESTAMP(3) NULL,
    locked_by  VARCHAR(255),
    PRIMARY KEY (name)
)

加锁

 @Scheduled(fixedDelay = 10*1000 /**ms**/,initialDelay = 10*1000)
    @SchedulerLock(name = "demoLockTask", lockAtMostFor = 5*1000)
    public void checkTask(){
        LOGGER.error("checkTask executed");
    }

动态添加关闭定时任务

// 引入定时调度线程池
@Autowired
private ThreadPoolTaskScheduler threadPoolTaskScheduler; 

// 接收线程调度返回的结果获取类
private ScheduledFuture future;

public void test(){
    // 如果已经有任务了就取消原有任务
    if (future != null) {
           future.cancel(true);
       }
    // 每月第一天
    String cron = "0 0 0 1 * ?";
    future = threadPoolTaskScheduler.schedule(new MyRunnable(), new CronTrigger(cron));
    // Runnable也可以写成lambda
    future = threadPoolTaskScheduler.schedule(()->{
            //do..
        }, new CronTrigger(cron));
    }

你可能感兴趣的:(Spring定时任务)