延迟队列DelayQueue

108 阅读2分钟

说到延迟队列,我第一时间想到的是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进行测试

image.png