baler项目总结-DelayQueue队列使用(一)

先看一段定义,
Delayed 元素的一个无界阻塞队列,只有在延迟期满时才能从中提取元素。该队列的头部 是延迟期满后保存时间最长的 Delayed 元素。如果延迟都还没有期满,则队列没有头部,并且 poll 将返回 null。

场景

  • 关闭空闲连接。服务器中,有很多客户端的连接,空闲一段时间之后需要关闭之。
  • 缓存。缓存中的对象,超过了空闲时间,需要从缓存中移出。
  • 任务超时处理。在网络协议滑动窗口请求应答式交互时,处理超时未响应的请求。

一种笨笨的办法就是,使用一个后台线程,遍历所有对象,挨个检查。这种笨笨的办法简单好用,但是对象数量过多时,可能存在性能问题,检查间隔时间不好设置,间隔时间过大,影响精确度,多小则存在效率问题。而且做不到按超时的时间顺序处理。

代码

需求

将一组数据设置一个倒计时时间,时间一到立刻消费这个数据。

实现

package com.eju.ess;

import java.util.Random;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import org.junit.Test;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Data
public class DataEntity implements Delayed{
    // 数据key
    private String dataKey;
    // 数据创建时间
    private long startTime;
    // 延迟多久执行
    private long delayTime;
    

    /**
     * 排序算法
     */
    @Override
    public int compareTo(Delayed o) {
        DataEntity that = (DataEntity) o;
        if (this.getTargetTime() < that.getTargetTime())
            return -1;
        if (this.getTargetTime() > that.getTargetTime())
            return 1;
        return 0;
    }
    
    /**
     * 计算目标执行时间和当前时间差
     */
    @Override
    public long getDelay(TimeUnit unit) {
        long result=unit.convert(this.getTargetTime() - System.currentTimeMillis(),TimeUnit.MILLISECONDS);
        return result;
    }
    
    private long getTargetTime(){
        return startTime + delayTime;
    }
    
    @Test
    public void test(){
        DelayQueue delayQueue=new DelayQueue();
        for(int i=0;i<=5;i++){
            DataEntity dataEntity=new DataEntity();
            dataEntity.setDataKey("数据 "+i);
            dataEntity.setStartTime(System.currentTimeMillis());
            int randomNum=new Random().nextInt(10);
            dataEntity.setDelayTime(randomNum*1000);
            log.info("{} 需要延迟 {}",dataEntity.getDataKey(),dataEntity.getDelayTime());
            delayQueue.put(dataEntity);
        }
        log.info("---------------------------------------");
        Executor executor=Executors.newCachedThreadPool();
        executor.execute(new Runnable() {
            @Override
            public void run() {
                while(true){
                    try {
                        DataEntity dataEntity=delayQueue.take();
                        log.info("{} 开始执行 ",dataEntity.getDataKey());
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        });
        
        try {
            TimeUnit.DAYS.sleep(Long.MAX_VALUE);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

参考

1,精巧好用的DelayQueue

==手机QQ扫描下方二维码,快速加入Java架构师交流群==

baler项目总结-DelayQueue队列使用(一)_第1张图片
image

你可能感兴趣的:(baler项目总结-DelayQueue队列使用(一))