说到延迟队列,我第一时间想到的是RabbitMQ中的延时队列。今天笔记的是:
java.util.concurrent.DelayQueue
1.创建延时队列中数据存储对象
实现Delayed接口,
重写
long getDelay(TimeUnit unit);获取任务剩余执行时间与
public int compareTo(T o);任务执行比较顺序
@Data
public class DelayTask<T> implements Delayed {
// 队列中存储的数据
private T data;
// 任务延迟时间(纳秒为单位)
private long deadlineNanos;
// 构造器
public DelayTask(T data, Duration delayTime) {
this.data = data;
this.deadlineNanos = System.nanoTime() + delayTime.toNanos();
}
// 计算延时时间还剩多少
@Override
public long getDelay(TimeUnit unit) {
return unit.convert(Math.max(0, deadlineNanos - System.nanoTime()), TimeUnit.NANOSECONDS);
}
// 延时队列排队比较
@Override
public int compareTo(Delayed o) {
long l = getDelay(TimeUnit.NANOSECONDS) - o.getDelay(TimeUnit.NANOSECONDS);
if (l > 0) {
return 1;
} else if (l < 0) {
return -1;
} else {
return 0;
}
}
}
2.创建延时队列,死循环阻塞处理队列任务,创建添加任务到队列的方法
@Component
@Slf4j
public class DelayTaskHandler {
// 初始化队列
private final DelayQueue<DelayTask<String>> queue = new DelayQueue<>();
// 项目启动死循环监视队列内容,死循环结束标记
// volatile 多线程下的可见性
private static volatile boolean begin = true;
// springboot项目启动初始化执行的方法
@PostConstruct
public void init() {
CompletableFuture.runAsync(this::handleDelayTask);
}
// springboot项目项目关闭执行的方法
@PreDestroy
public void destroy() {
begin = false;
}
// 执行延迟队列方法
public void handleDelayTask() {
log.info("启动延时任务");
while (begin) {
try {
// 延时队列阻塞等待任务
DelayTask<String> take = queue.take();
// 获取任务
String data = take.getData();
log.info("{}的延时任务执行啦,时间:{}", data, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSS").format(LocalDateTime.now()));
} catch (InterruptedException e) {
log.error("延时队列发生了异常:{}", e.getMessage());
// throw new RuntimeException(e);
}
}
log.info("关闭延时任务");
}
// 提交延迟任务到延迟队列 DelayQueue
public void addDelayTask(String data) {
queue.add(new DelayTask<>(data, Duration.ofSeconds(5)));
}
}
3.创建一个接口,请求访问添加延时任务到队列中,进行测试
@RestController
@RequestMapping("/delay")
@Slf4j
@RequiredArgsConstructor
public class DelayController {
private final DelayTaskHandler delayTaskHandler;
@GetMapping("/{name}")
public String delay(@PathVariable("name") String name) {
delayTaskHandler.addDelayTask(name);
return name + "任务执行完成";
}
}
4.使用jmeter进行测试