【无标题】Delayed延迟队列不工作

背景

项目中使用java 自带的延迟队列Delayed,只有添加进队列的消息,并没有被消费到

版本

jdk1.8

问题原因

上一个消费队列出现异常并且没有捕获,下一个队列就没有进行消费

复现代码

没有抛异常的情况下

package com.ccb.core.config.delay;

import lombok.Data;

import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;

/**
 * 防护舱延迟对象
 *
 * @author sz
 * @version 1.0
 * @date 2023-02-10 15:47
 */
@Data
public class TestDelay implements Delayed {


     private  String seqId;
    /**
    *过期时间
    */
    private Long expireTime;
    @Override
    public long getDelay(TimeUnit unit) {
        return unit.convert(this.expireTime - System.currentTimeMillis() , TimeUnit.MILLISECONDS);
    }

    @Override
    public int compareTo(Delayed other) {
        if (other == this){
            return 0;
        }
        if(other instanceof TestDelay){
            TestDelay otherRequest = (TestDelay)other;
            long otherStartTime = otherRequest.expireTime;
            return (int)(this.expireTime - otherStartTime);
        }
        return 0;
    }
}


package com.ccb.core.config.delay;

import com.ccb.core.common.util.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Executor;

/**
 * @author sz
 * @version 1.0
 * @date 2023-10-08 19:12
 */
@Slf4j
@Component
public class ProtectDelayTestComponent {

    private static DelayQueue<TestDelay> delayQueue = new DelayQueue<TestDelay>();

    @Resource(name = "poiExecutor")
    private Executor poiExecutor;

    /**
     * 系统启动时,预先加载的数据@PostConstruct
     */
    @PostConstruct
    public void init(){

        log.info("线程进入ProtectDelayTestComponent***************init");

        poiExecutor.execute(() -> {

            while(true){
                try {
                    TestDelay protectDelay = delayQueue.take();
                    log.info("获取到的延迟队列信息:{}", protectDelay);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

    }

    /**
     * 加入延时队列
     *
     */
    public boolean addDelayQueue(TestDelay protectDelay){
        log.info("添加进延迟队列信息为{},对应的过期时间为:{}",protectDelay, DateUtil.convertTimeToString(protectDelay.getExpireTime(),"yyyy-MM-dd HH:mm:ss"));
        return delayQueue.add(protectDelay);
    }
}

 /**
     * poi线程池设置 由spring容器进行管理
     * @return
     */
    @Bean("poiExecutor")
    public Executor poiExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(8);
        executor.setMaxPoolSize(16);
        executor.setQueueCapacity(1000);
        executor.setKeepAliveSeconds(60);
        executor.setAllowCoreThreadTimeOut(true);
        executor.setThreadNamePrefix("poiExecutor-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }

写TestController 测试正常的添加进入延迟队列

  @GetMapping("/test/testProtectDelay")
    @ApiModelProperty("测试批量死信队列")
    public RespData testProtectDelay(){
        TestDelay protectDelay =new TestDelay();
        String s = UuidUtils.generateUuid();
        log.info("testProtectDelay的参数:{}",s);
        protectDelay.setSeqId(s);
        protectDelay.setExpireTime(System.currentTimeMillis()+10*1000);
        protectDelayTestComponent.addDelayQueue(protectDelay);
        return RespData.success();
    }

正常运行结果
在这里插入图片描述

手动抛出异常后

在这里插入图片描述

解决方案

在take中捕获Exception ,可以继续消费

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
非常抱歉,我理解错了你的意思。以下是一个简单的Java代码示例,用于从线程池的延迟队列中删除一条数据: ```java import java.util.concurrent.DelayQueue; import java.util.concurrent.Delayed; import java.util.concurrent.TimeUnit; public class ThreadPoolDelayQueueExample { private static DelayQueue<DelayedTask> delayQueue = new DelayQueue<>(); public static void main(String[] args) { // 添加一些任务到延迟队列delayQueue.put(new DelayedTask("task1", 10, TimeUnit.SECONDS)); delayQueue.put(new DelayedTask("task2", 20, TimeUnit.SECONDS)); delayQueue.put(new DelayedTask("task3", 30, TimeUnit.SECONDS)); // 从延迟队列中删除一条数据 String taskId = "task2"; for (DelayedTask task : delayQueue) { if (task.getTaskId().equals(taskId)) { delayQueue.remove(task); break; } } } static class DelayedTask implements Delayed { private String taskId; private long delayTime; public DelayedTask(String taskId, long delayTime, TimeUnit timeUnit) { this.taskId = taskId; this.delayTime = System.currentTimeMillis() + TimeUnit.MILLISECONDS.convert(delayTime, timeUnit); } public String getTaskId() { return taskId; } @Override public long getDelay(TimeUnit unit) { return unit.convert(delayTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS); } @Override public int compareTo(Delayed o) { return Long.compare(this.delayTime, ((DelayedTask) o).delayTime); } } } ``` 以上代码中,我们使用了Java的`DelayQueue`来实现线程池的延迟队列。我们先添加了三个任务到延迟队列中,然后根据任务ID从队列中找到对应的任务,并通过`remove`方法删除它。 需要注意的是,我们在`DelayedTask`类中实现了`Delayed`接口,并重写了`getDelay`和`compareTo`方法。`getDelay`方法返回任务的剩余延迟时间,`compareTo`方法比较两个任务的延迟时间大小。`DelayQueue`会根据任务的延迟时间自动排序,保证最先过期的任务会被取出执行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值