java 定时任务的几种实现方式

Python09

java 定时任务的几种实现方式,第1张

JDK 自带的定时器实现

// schedule(TimerTask task, long delay) 延迟 delay 毫秒 执行

// schedule(TimerTask task, Date time) 特定时间执行

public static void main(String[] args) {

for (int i = 0i <10++i) {

new Timer("timer - " + i).schedule(new TimerTask() {

@Override

public void run() {

println(Thread.currentThread().getName() + " run ")

}

}, 1000)

}

}

2. Quartz 定时器实现

//首先我们需要定义一个任务类,比如为MyJob02 ,

//该类需要继承Job类,然后添加execute(JobExecutionContext context)方法,在

//这个方法中就是我们具体的任务执行的地方。

//由希望由调度程序执行的组件实现的接口

public class MyJob02 implements Job {

@Override

public void execute(JobExecutionContext context) throws JobExecutionException {

// TODO Auto-generated method stub

// 执行响应的任务.

System.out.println("HelloJob.execute,"+new Date())

}

}

public class QuartzTest5 {

public static void main(String[] args) throws Exception {

//SchedulerFactory 是一个接口,用于Scheduler的创建和管理

SchedulerFactory factory = new StdSchedulerFactory()

//从工厂里面拿到一个scheduler实例

//计划表(可能翻译的不太贴切),现在我们有了要做的内容,

//与调度程序交互的主要API

/*

* Scheduler的生命期,从SchedulerFactory创建它时开始,

到Scheduler调用shutdown()方法时结束;Scheduler被创建后,

可以增加、删除和列举Job和Trigger,以及执行其它与调度相关的操作

(如暂停Trigger)。但是,Scheduler只有在调用start()方法后,

才会真正地触发trigger(即执行job)

*/

Scheduler scheduler = factory.getScheduler()

//具体任务.

//用于定义作业的实例

//JobBuilder - 用于定义/构建JobDetail实例,用于定义作业的实例。

JobDetail job = JobBuilder.newJob(MyJob.class).withIdentity("job1", "group1").build()

//Trigger(即触发器) - 定义执行给定作业的计划的组件

//TriggerBuilder - 用于定义/构建触发器实例

CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1")

.withSchedule(CronScheduleBuilder.cronSchedule("0/1  * * * * ?")).build()

scheduler.scheduleJob(job, trigger)

scheduler.start()

}

3. Spring  boot 任务调度(这个非常容易实现)

/*

*  开启对定时任务的支持

*  在相应的方法上添加@Scheduled声明需要执行的定时任务。

*/

@EnableScheduling

//@EnableScheduling注解来开启对计划任务的支持

public class Application {

public static void main(String[] args) {

SpringApplication.run(Application.class, args)

}

}

@Component

public class ScheduledTasks {

private Logger logger = LoggerFactory.getLogger(ScheduledTasks.class)

private    int     i=0

//0 0 0 2 * ?

@Scheduled(cron="*  *  *  2  *  ?")

//@Scheduled 注解用于标注这个方法是一个定时任务的方法

public void testFixDelay() {

logger.info("执行方法"+i++)

}

1、ZSet 实现方式

通过 ZSet 实现定时任务的思路是,将定时任务存放到 ZSet 集合中,并且将过期时间存储到 ZSet 的 Score 字段中,然后通过一个无线循环来判断当前时间内是否有需要执行的定时任务,如果有则进行执行,具体实现代码如下:

import redis.clients.jedis.Jedis

import utils.JedisUtils

import java.time.Instant

import java.util.Set

public class DelayQueueExample {

private static final String _KEY = "DelayQueueExample"

public static void main(String[] args) throws InterruptedException {

Jedis jedis = JedisUtils.getJedis()

// 30s 后执行

long delayTime = Instant.now().plusSeconds(30).getEpochSecond()

jedis.zadd(_KEY, delayTime, "order_1")

// 继续添加测试数据

jedis.zadd(_KEY, Instant.now().plusSeconds(2).getEpochSecond(), "order_2")

jedis.zadd(_KEY, Instant.now().plusSeconds(2).getEpochSecond(), "order_3")

jedis.zadd(_KEY, Instant.now().plusSeconds(7).getEpochSecond(), "order_4")

jedis.zadd(_KEY, Instant.now().plusSeconds(10).getEpochSecond(), "order_5")

// 开启定时任务队列

doDelayQueue(jedis)

}

/**

* 定时任务队列消费

* @param jedis Redis 客户端

*/

public static void doDelayQueue(Jedis jedis) throws InterruptedException {

while (true) {

// 当前时间

Instant nowInstant = Instant.now()

long lastSecond = nowInstant.plusSeconds(-1).getEpochSecond()

// 上一秒时间

long nowSecond = nowInstant.getEpochSecond()

// 查询当前时间的所有任务

Set data = jedis.zrangeByScore(_KEY, lastSecond, nowSecond)

for (String item : data) {

// 消费任务

System.out.println("消费:" + item)

}

// 删除已经执行的任务

jedis.zremrangeByScore(_KEY, lastSecond, nowSecond)

Thread.sleep(1000)// 每秒查询一次

}

}

}

登录后复制

2、键空间通知

我们可以通过 Redis 的键空间通知来实现定时任务,它的实现思路是给所有的定时任务设置一个过期时间,等到了过期之后,我们通过订阅过期消息就能感知到定时任务需要被执行了,此时我们执行定时任务即可。

默认情况下 Redis 是不开启键空间通知的,需要我们通过 config set notify-keyspace-events Ex 的命令手动开启,开启之后定时任务的代码如下