java實現帶過時時間的緩存

private static ScheduledExecutorService swapExpiredPool
            = new ScheduledThreadPoolExecutor(10);
 
    private ReentrantLock lock = new ReentrantLock();
 
    private ConcurrentHashMap<String, Node> cache = new ConcurrentHashMap<>(1024);
    /**
     * 讓過時時間最小的數據排在隊列前,在清除過時數據時
     * ,只需查看緩存最近的過時數據,而不用掃描所有緩存
     *
     * @see Node#compareTo(Node)
     * @see SwapExpiredNodeWork#run()
     */
    private PriorityQueue<Node> expireQueue = new PriorityQueue<>(1024);
 
    public LocalCache() {
 
        //使用默認的線程池,每5秒清除一次過時數據
        //線程池和調用頻率 最好是交給調用者去設置。
        swapExpiredPool.scheduleWithFixedDelay(
                new SwapExpiredNodeWork(), 5, 5, TimeUnit.SECONDS);
    }
 
    public Object set(String key, Object value, long ttl) {
 
        Assert.isTrue(StringUtils.hasLength(key), "key can't be empty");
        Assert.isTrue(ttl > 0, "ttl must greater than 0");
 
        long expireTime = System.currentTimeMillis() + ttl;
        Node newNode = new Node(key, value, expireTime);
        lock.lock();
        try {
            Node old = cache.put(key, newNode);
            expireQueue.add(newNode);
            //若是該key存在數據,還要從過時時間隊列刪除
            if (old != null) {
                expireQueue.remove(old);
                return old.value;
            }
            return null;
        } finally {
            lock.unlock();
        }
 
    }
 
    /**
     * 拿到的數據多是已通過期的數據,能夠再次判斷一下
     * if(n.expireTime<System.currentTimeMillis()){
     * return null;
     * }
     * 也能夠直接返回整個節點Node ,交給調用者去取捨
     * <p>
     * <p>
     * 沒法判斷不存在該key,仍是該key存的是一個null值,若是須要區分這兩種狀況
     * 能夠定義一個全局標識,標識key不存在
     * public static final NOT_EXIST = new Object();
     * 返回值時
     * return n==null?NOT_EXIST:n.value;
     */
    public Object get(String key) {
        Node n = cache.get(key);
        return n == null ? null : n.value;
    }
 
    /**
     * 刪出KEY,並返回該key對應的數據
     */
    public Object remove(String key) {
        lock.lock();
        try {
            Node n = cache.remove(key);
            if (n == null) {
                return null;
            } else {
                expireQueue.remove(n);
                return n.value;
            }
        } finally {
            lock.unlock();
        }
    }
 
    /**
     * 刪除已通過期的數據
     */
    private class SwapExpiredNodeWork implements Runnable {
 
        @Override
        public void run() {
 
            long now = System.currentTimeMillis();
            while (true) {
                lock.lock();
                try {
                    Node node = expireQueue.peek();
                    //沒有數據了,或者數據都是沒有過時的了
                    if (node == null || node.expireTime > now) {
                        return;
                    }
                    cache.remove(node.key);
                    expireQueue.poll();
 
                } finally {
                    lock.unlock();
                }
            }
        }
    }
 
 
    private static class Node implements Comparable<Node> {
        private String key;
        private Object value;
        private long expireTime;
 
        public Node(String key, Object value, long expireTime) {
            this.value = value;
            this.key = key;
            this.expireTime = expireTime;
        }
 
 
        /**
         * @see SwapExpiredNodeWork
         */
        @Override
        public int compareTo(Node o) {
            long r = this.expireTime - o.expireTime;
            if (r > 0) {
                return 1;
            }
            if (r < 0) {
                return -1;
            }
            return 0;
        }
 
    }
相關文章
相關標籤/搜索