Java進程內緩存


今天和同事聊到了緩存,在Java中實現進程緩存。這里主要思想是,用一個map做緩存。緩存有個生存時間,過期就刪除緩存。這里可以考慮兩種刪除策略,一種是起一個線程,定期刪除過期的key。第二個是,剔除模式,比較懶,訪問到某個key的時候才,才去檢查這個key是否過期,過期刪除。

首先,對要緩存的value做了層封裝,帶了個時間戳

/**
 * Created by gxf on 2017/6/28.
 */
public class ValueWithTimeStamp<V>{
    private long expireTime;
    private V value;

    public ValueWithTimeStamp(long expireTime, V value) {
        this.expireTime = expireTime;
        this.value = value;
    }

    public long getExpireTime() {
        return expireTime;
    }

    public void setExpireTime(long expireTime) {
        this.expireTime = expireTime;
    }

    public V getValue() {
        return value;
    }

    public void setValue(V value) {
        this.value = value;
    }
}

ok,起線程定期刪除策略的模式

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by gxf on 2017/6/28.
 * 使用線程,定期刪除過期的key
 */
public class CacheMap<K, V>  {
    //這里使用ConcurrentHashMap避免,clean的時候,主線程修改chache,造成異常,
    //使用ConcurrentHashMap可以控制並發修改cache
    private Map<K, ValueWithTimeStamp<V>> cache = new ConcurrentHashMap<K, ValueWithTimeStamp<V>>();
    private static boolean cleanTaskIsRunning = false;

    //ttl 過期時間 單位:秒
    public void put(K key, V value, int ttl){
        long expireTime = System.currentTimeMillis() + ttl * 1000;
        ValueWithTimeStamp<V> valueWithTimeStamp = new ValueWithTimeStamp<>(expireTime, value);
        cache.put(key, valueWithTimeStamp);
        if(!cleanTaskIsRunning){
            startCleanTask();
            cleanTaskIsRunning = !cleanTaskIsRunning;
        }
    }

    public V get(K key){
        ValueWithTimeStamp<V> valueWithTimeStamp = cache.get(key);
        return null == valueWithTimeStamp ? null : valueWithTimeStamp.getValue();
    }

    /**
     * 啟動清理線程
     * */
    private void startCleanTask(){
        Thread cleanThread = new Thread(new CleanTask());
        cleanThread.start();
    }

    /**
     * 清理過期的key
     * */
    class CleanTask implements Runnable{
        public void run(){
            while(true){
                long currentTime =  System.currentTimeMillis();
                //遍歷map
                for(Map.Entry<K, ValueWithTimeStamp<V>> entry : cache.entrySet()){
                    ValueWithTimeStamp<V> valueWithTimeStamp = entry.getValue();
                    long expireTime = valueWithTimeStamp.getExpireTime();
                    //過期時間到了
                    if(currentTime > expireTime){
                        System.out.println("key : " + entry.getKey() + " expired ");
                        cache.remove(entry.getKey());
                    } //if
                } //for
                //每隔1s掃描map對象
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } //while
        }
    }
}

注意,這里需要使用ConcurrentHashMap做緩存。不然會出現多線線程操作map對象的異常

第二種策略,剔除模式

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by 58 on 2017/6/28.
 * 這里使用懶惰模式,獲取key的時候,才剔除過期的key
 */
public class CacheMap1<K, V> {
    private Map<K, ValueWithTimeStamp<V>> cache = new ConcurrentHashMap<K, ValueWithTimeStamp<V>>();

    public void put(K key, V value, int ttl){
        long expireTime = System.currentTimeMillis() + ttl * 1000;
        ValueWithTimeStamp<V> valueWithTimeStamp = new ValueWithTimeStamp<V>(expireTime, value);
        cache.put(key, valueWithTimeStamp);
    }

    public V get(K key){
        ValueWithTimeStamp<V> valueWithTimeStamp = cache.get(key);
        long expireTime = valueWithTimeStamp.getExpireTime();
        long currentTime = System.currentTimeMillis();
        //key已經過期,刪除,返回null
        if(currentTime > expireTime){
            System.out.println("key :" + key + " is expired.");
            cache.remove(key);
            return null;
        }

        return cache.get(key).getValue();
    }
}

項目中用到了redis,用這種方式應該會更快,這兩天優化一下代碼


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM