• DelayQueue延迟队列-实现缓存


    延迟阻塞队列DelayQueue

    DelayQueue 是一个支持延时获取元素的阻塞队列,
    内部采用优先队列 PriorityQueue 存储元素,
    同时元素必须实现 Delayed 接口;在创建元素时可以指定多久才可以从队列中获取当前元素,只有在延迟期满时才能从队列中提取元素。

    使用场景

    • 缓存系统:当能够从延迟队列DelayQueue中获取到元素时,说明缓存已经过期
    • 定时任务调度:一分钟后发送短信

    基于延迟队列,实现一个缓存系统

    延迟队列中添加的元素,实现了Delayed接口

    public class CacheItem implements Delayed{
    	private long expireTime;
    	
    	private long currentTime;
    	
    	private String key;
    	
    	public String getKey() {
    		return key;
    	}
    	
    	public CacheItem(String key,long expireTime) {
    		this.key = key;
    		this.expireTime = expireTime;
    		this.currentTime = System.currentTimeMillis();
    	}
    
    	/**
    	 * 比较方法,用于排序
    	 * 过期时间长的放队尾,时间短的放队首
    	 */
    	@Override
    	public int compareTo(Delayed o) {
    		if(this.getDelay(TimeUnit.MICROSECONDS) > o.getDelay(TimeUnit.MICROSECONDS))
    			return 1;
    		if(this.getDelay(TimeUnit.MICROSECONDS) > o.getDelay(TimeUnit.MICROSECONDS))
    			return -1;
    		return 0;
    	}
    
    	/**
    	 * 计算剩余的过期时间
    	 * 大于0说明没有过期
    	 */
    	@Override
    	public long getDelay(TimeUnit unit) {
    		
    		return expireTime - unit.MILLISECONDS.toSeconds(System.currentTimeMillis()-currentTime);
    		
    	}
    
    }
    
    

    缓存实现

    public class DelayQueueDemo {
    	static class Cache implements Runnable{
    		private Map<String,String> itemMap = new HashMap<>();
    	
    		private DelayQueue<CacheItem> delayQueue = new DelayQueue<>();
    		
    		private boolean stop = false;
    		
    		// 初始化后就开始检测
    		public Cache() {
    			new Thread(this).start();
    		}
    		
    		public void add(String key,String value,long expireTime) {
    			CacheItem item = new CacheItem(key,expireTime);
    			itemMap.put(key, value);
    			delayQueue.add(item);
    			
    		}
    		
    		public String get(String key) {
    			return itemMap.get(key);
    		}
    		
    		public void shutdown() {
    			stop = true;
    		}
    		
    		// 开启多线程,检测缓存是否过期
    		@Override
    		public void run() {
    			while(!stop) {
    				CacheItem item = delayQueue.poll();
    				if(item != null) {
    					// 缓存过期
    					 itemMap.remove(item.getKey());
    					 System.out.println("delete expired key:"+item.getKey());
    				}
    			}
    			System.out.println("Cache stop");
    		}
    	}
    	
    	public static void main(String[] args) throws Exception{
    		Cache cache = new Cache();
    		cache.add("a", "1", 1);
    		cache.add("b", "2", 2);
    		cache.add("c", "3", 2);
    		cache.add("d", "4", 4);
    		cache.add("e", "5", 6);
    		
    		while(true) {
    			String a = cache.get("a");
    			String b = cache.get("b");
    			String c = cache.get("c");
    			String d = cache.get("d");
    			String e = cache.get("e");
    			
    			if(a == null && b == null && c == null && d == null && e == null) {
    				break;
    			}
    		}
    		
    		TimeUnit.SECONDS.sleep(1);
    		cache.shutdown();
    	}
    	
    }
    
    

    延迟队列实现原理部分说明

    • 可重入锁 ReentrantLock
    • 优先队列 PriorityQueue

    参考连接

  • 相关阅读:
    git下载指定的版本
    QT中定时器
    makefile 中添加依赖的库文件
    Qt 出现“undefined reference to `vtable for”
    qt程序启动播放动画
    常用正则表达式
    当你纠结时,请打开这31个锦…
    android mk详解
    C++日志系统log4cxx使用总结
    qt 坐标变换
  • 原文地址:https://www.cnblogs.com/watertreestar/p/11780249.html
Copyright © 2020-2023  润新知