Java代码实现Cache

本文参考网络上其它文章,仅做部分代码修改及优化,加入个人编码习惯,感谢那些乐于分享的大佬吧

package com.yt.test.callback2;

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

/**
 * 延迟队列元素,未达到指定时间,则不可使用此对象,单独使用也是不错的工具类
 * 
 * @author ChenSS on 2017年9月13日
 * @param <T>
 */
public class DelayItem<T> implements Delayed {
    private long timeout;
    private long endTime;

    private T item;

    public DelayItem(T item, long timeout) {
        this.item = item;
        this.timeout = timeout;
        this.endTime = System.nanoTime() + TimeUnit.NANOSECONDS.convert(timeout, TimeUnit.MILLISECONDS);
    }

    public DelayItem(T item, long timeout, TimeUnit unit) {
        this.item = item;
        this.timeout = timeout;
        this.endTime = System.nanoTime() + TimeUnit.NANOSECONDS.convert(timeout, unit);
    }

    public T getItem() {
        return this.item;
    }

    public long getTimeout() {
        return timeout;
    }

    /**
     * 重置结束时间
     * 
     * @throws TimeoutException
     *             如果已经结束,不可被重置
     */
    public void reset() throws TimeoutException {
        if (System.nanoTime() > endTime)
            throw new TimeoutException("The current object has timeout, can not be reset");
        this.endTime = System.nanoTime() + TimeUnit.NANOSECONDS.convert(timeout, TimeUnit.MILLISECONDS);
    }

    /**
     * 预计结束时间-当前时间 = 剩余停滞时间(当数值小于零时此对象可用)
     * 
     * @return 纳秒(未达到超时时间对象不可用)
     */
    @Override
    public long getDelay(TimeUnit unit) {
        return unit.convert((endTime - System.nanoTime()), TimeUnit.NANOSECONDS);
    }

    /**
     * 取出结束时间最早的
     */
    @Override
    public int compareTo(Delayed other) {
        if (other == this)
            return 0;
        if (other instanceof DelayItem) {
            long diff = endTime - ((DelayItem<?>) other).endTime;
            return (diff == 0) ? 0 : ((diff < 0) ? -1 : 1);
        }
        long diff = (getDelay(TimeUnit.NANOSECONDS) - other.getDelay(TimeUnit.NANOSECONDS));
        return (diff == 0) ? 0 : ((diff < 0) ? -1 : 1);
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((item == null) ? 0 : item.hashCode());
        return result;
    }

    /**
     * 重写此方法方便在多数集合中以Item值比较DelayItem是否是同一个
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        DelayItem<?> other = (DelayItem<?>) obj;
        if (item == null) {
            if (other.item != null)
                return false;
        } else if (!item.equals(other.item))
            return false;
        return true;
    }
}

 

package com.yt.test.callback2;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.naming.TimeLimitExceededException;

/**
 * 
 * @author ChenSS on 2017年9月13日
 * @param <K>
 * @param <V>
 */
public class Cache<K, V> {
    private Logger logger = Logger.getLogger(Cache.class.getName());
    private DelayQueue<DelayItem<K>> q = new DelayQueue<>();
    /**
     * 多线程安全的Maps
     */
    private ConcurrentMap<K, V> maps = new ConcurrentHashMap<K, V>();
    private long liveTime;
    /**
     * 守护进程
     */
    private Thread daemonThread;

    public Cache(long liveTime) {
        this.liveTime = liveTime;
        Runnable daemonTask = new Runnable() {
            public void run() {
                daemonCheck();
            }
        };
        daemonThread = new Thread(daemonTask);
        daemonThread.setDaemon(true);
        daemonThread.setName("Cache Daemon");
        daemonThread.start();
    }

    public void put(K key, V value) {
        this.put(key, value, liveTime, TimeUnit.MILLISECONDS);
    }

    public void put(K key, V value, long outtime) {
        this.put(key, value, outtime, TimeUnit.MILLISECONDS);
    }

    public void put(K key, V value, long outtime, TimeUnit timeUnit) {
        if (outtime <= 0) {
            try {
                throw new TimeLimitExceededException("Cache livetime below 0");
            } catch (TimeLimitExceededException e) {
                e.printStackTrace();
            }
        }
        V oldValue = maps.put(key, value);
        if (oldValue != null)
            q.remove(key);
        q.put(new DelayItem<K>(key, outtime, timeUnit));
    }

    public V get(K key) {
        return maps.get(key);
    }

    private void daemonCheck() {
        if (logger.isLoggable(Level.INFO))
            logger.info("cache service started.");
        for (;;) {
            try {
                DelayItem<K> delayItem = q.take();
                if (delayItem != null)
                    maps.remove(delayItem.getItem());
            } catch (InterruptedException e) {
                if (logger.isLoggable(Level.SEVERE))
                    logger.log(Level.SEVERE, e.getMessage(), e);
                e.printStackTrace();
                break;
            }
        }
        if (logger.isLoggable(Level.INFO))
            logger.info("cache service stopped.");
    }
}

 

 

package com.yt.test.callback2;

public class Test {
    public static void main(String[] args) throws InterruptedException {
        Cache<String, Integer> cache = new Cache<>(4000);
        cache.put("AAAA", 3);
        cache.put("BBBB", 4, 4000);
        System.out.println(cache.get("AAAA"));
        
        Thread.sleep(3000);
        System.out.println(cache.get("BBBB"));
        
        Thread.sleep(1200);
        System.out.println(cache.get("AAAA"));
        System.out.println(cache.get("BBBB"));
    }
}

 

posted on 2017-09-13 23:42  疯狂的妞妞  阅读(495)  评论(0编辑  收藏  举报

导航