有什么方式实现实时任务?
1、Java中的几种实现方式
1.1、Timer类
public class TestTimer {
static int i = 0;
public static void main(String[] args) {
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
System.out.println("执行任务:" + i++);
}
};
Timer timer = new Timer();
timer.schedule(timerTask, 10, 3000);
}
}
1.2、ScheduledExecutorService
public void schedule() {
ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
service.scheduleAtFixedRate(() ->
System.out.println("定时执行"), 0, 3, TimeUnit.SECONDS);
}
1.3、利用spring的@Schedule( cron = “0 0/10 * * * ?” )
(在使用zset中代码示例)
1.4、DequeQueue
实现Deque接口。使用DequeQueue延时队列
2、redis使用zset
在Redis中,zet作为有序集合,可以利用其有序的特性,将任务添加到zset中,将任务的到期时间作为score,利用zset的默认有序特性,zrangewithscores可以获取score值最小的元素(也就是最近到期的任务),判断系统时间与该任务的到期时间大小,如果达到到期时间,就执行业务,并删除该到期任务,继续判断下一个元素,如果没有到期,就sleep一段时间(比如1秒),如果集合为空,也sleep一段时间。
附: 简单的延时队列的需求:如何实现对下单超过15分钟没有支付的订单进行取消操作
1、使用zset数据结构存储,订单号为key,时间为score。
2、新增订单的时候,将订单号插入zset。
3、设定轮询,每分钟轮询一次zset,找出score小于当前秒数的数据,进行处理,然后将key在zset内删除。
创建定时任务:
@Component
@EnableScheduling
public class ScheduleTask {
@Autowired
private RedisTemplate redisTemplate;
@Scheduled(cron = "* * * * * *")
public void schedule() {
ZSetOperations zSetOperations = redisTemplate.opsForZSet();
Set<String> task = zSetOperations.
rangeByScore("task", 0, System.currentTimeMillis());
Iterator<String> iterator = task.iterator();
while (iterator.hasNext()) {
String curTask = iterator.next();
System.out.println(curTask);
zSetOperations.remove("task", curTask);
}
}
}
增加延时任务:
@ResponseBody
@GetMapping("/addTask")
public String redisAddTask(Long time, String taskName) {
ZSetOperations zSetOperations = redisTemplate.opsForZSet();
zSetOperations.add("task", taskName, System.currentTimeMillis() + time);
return taskName;
}