<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    莊周夢蝶

    生活、程序、未來
       :: 首頁 ::  ::  :: 聚合  :: 管理
    update1:第二個實(shí)現(xiàn),讀操作不必要采用獨(dú)占鎖,緩存顯然是讀多于寫,讀的時候一開始用獨(dú)占鎖是考慮到要遞增計(jì)數(shù)和更新時間戳要加鎖,不過這兩個變量都是采用原子變量,因此也不必采用獨(dú)占鎖,修改為讀寫鎖。
    update2:一個錯誤,老是寫錯關(guān)鍵字啊,LRUCache的maxCapacity應(yīng)該聲明為volatile,而不是transient。
      
       最簡單的LRU算法實(shí)現(xiàn),就是利用jdk的LinkedHashMap,覆寫其中的removeEldestEntry(Map.Entry)方法即可,如下所示:
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.LinkedHashMap;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    import java.util.Map;


    /**
     * 類說明:利用LinkedHashMap實(shí)現(xiàn)簡單的緩存, 必須實(shí)現(xiàn)removeEldestEntry方法,具體參見JDK文檔
     * 
     * 
    @author dennis
     * 
     * 
    @param <K>
     * 
    @param <V>
     
    */
    public class LRULinkedHashMap<K, V> extends LinkedHashMap<K, V> {
        
    private final int maxCapacity;

        
    private static final float DEFAULT_LOAD_FACTOR = 0.75f;

        
    private final Lock lock = new ReentrantLock();

        
    public LRULinkedHashMap(int maxCapacity) {
            
    super(maxCapacity, DEFAULT_LOAD_FACTOR, true);
            
    this.maxCapacity = maxCapacity;
        }

        @Override
        
    protected boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest) {
            
    return size() > maxCapacity;
        }
        @Override
        
    public boolean containsKey(Object key) {
            
    try {
                lock.lock();
                
    return super.containsKey(key);
            } 
    finally {
                lock.unlock();
            }
        }

        
        @Override
        
    public V get(Object key) {
            
    try {
                lock.lock();
                
    return super.get(key);
            } 
    finally {
                lock.unlock();
            }
        }

        @Override
        
    public V put(K key, V value) {
            
    try {
                lock.lock();
                
    return super.put(key, value);
            } 
    finally {
                lock.unlock();
            }
        }

        
    public int size() {
            
    try {
                lock.lock();
                
    return super.size();
            } 
    finally {
                lock.unlock();
            }
        }

        
    public void clear() {
            
    try {
                lock.lock();
                
    super.clear();
            } 
    finally {
                lock.unlock();
            }
        }

        
    public Collection<Map.Entry<K, V>> getAll() {
            
    try {
                lock.lock();
                
    return new ArrayList<Map.Entry<K, V>>(super.entrySet());
            } 
    finally {
                lock.unlock();
            }
        }
    }
        如果你去看LinkedHashMap的源碼可知,LRU算法是通過雙向鏈表來實(shí)現(xiàn),當(dāng)某個位置被命中,通過調(diào)整鏈表的指向?qū)⒃撐恢谜{(diào)整到頭位置,新加入的內(nèi)容直接放在鏈表頭,如此一來,最近被命中的內(nèi)容就向鏈表頭移動,需要替換時,鏈表最后的位置就是最近最少使用的位置。
        LRU算法還可以通過計(jì)數(shù)來實(shí)現(xiàn),緩存存儲的位置附帶一個計(jì)數(shù)器,當(dāng)命中時將計(jì)數(shù)器加1,替換時就查找計(jì)數(shù)最小的位置并替換,結(jié)合訪問時間戳來實(shí)現(xiàn)。這種算法比較適合緩存數(shù)據(jù)量較小的場景,顯然,遍歷查找計(jì)數(shù)最小位置的時間復(fù)雜度為O(n)。我實(shí)現(xiàn)了一個,結(jié)合了訪問時間戳,當(dāng)最小計(jì)數(shù)大于MINI_ACESS時(這個參數(shù)的調(diào)整對命中率有較大影響),就移除最久沒有被訪問的項(xiàng):
    package net.rubyeye.codelib.util.concurrency.cache;

    import java.io.Serializable;
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.Set;
    import java.util.concurrent.atomic.AtomicInteger;
    import java.util.concurrent.atomic.AtomicLong;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReadWriteLock;
    import java.util.concurrent.locks.ReentrantLock;
    import java.util.concurrent.locks.ReentrantReadWriteLock;

    /**
     * 
     * 
    @author dennis 類說明:當(dāng)緩存數(shù)目不多時,才用緩存計(jì)數(shù)的傳統(tǒng)LRU算法
     * 
    @param <K>
     * 
    @param <V>
     
    */
    public class LRUCache<K, V> implements Serializable {

        
    private static final int DEFAULT_CAPACITY = 100;

        
    protected Map<K, ValueEntry> map;

        
    private final ReadWriteLock lock = new ReentrantReadWriteLock();

        
    private final Lock readLock = lock.readLock();

        
    private final Lock writeLock = lock.writeLock();

        
    private final volatile int maxCapacity;  //保持可見性

        
    public static int MINI_ACCESS = 5;

        
    public LRUCache() {
            
    this(DEFAULT_CAPACITY);
        }

        
    public LRUCache(int capacity) {
            
    if (capacity <= 0)
                
    throw new RuntimeException("緩存容量不得小于0");
            
    this.maxCapacity = capacity;
            
    this.map = new HashMap<K, ValueEntry>(maxCapacity);
        }

        
    public boolean ContainsKey(K key) {
            
    try {
                readLock.lock();
                
    return this.map.containsKey(key);
            } 
    finally {
                readLock.unlock();
            }
        }

        
    public V put(K key, V value) {
            
    try {
                writeLock.lock();
                
    if ((map.size() > maxCapacity - 1&& !map.containsKey(key)) {
                    
    // System.out.println("開始");
                    Set<Map.Entry<K, ValueEntry>> entries = this.map.entrySet();
                    removeRencentlyLeastAccess(entries);
                }
                ValueEntry new_value 
    = new ValueEntry(value);
                ValueEntry old_value 
    = map.put(key, new_value);
                
    if (old_value != null) {
                    new_value.count 
    = old_value.count;
                    
    return old_value.value;
                } 
    else
                    
    return null;
            } 
    finally {
                writeLock.unlock();
            }
        }

        
    /**
         * 移除最近最少訪問
         
    */
        
    protected void removeRencentlyLeastAccess(
                Set
    <Map.Entry<K, ValueEntry>> entries) {
            
    // 最小使用次數(shù)
            long least = 0;
            
    // 訪問時間最早
            long earliest = 0;
            K toBeRemovedByCount 
    = null;
            K toBeRemovedByTime 
    = null;
            Iterator
    <Map.Entry<K, ValueEntry>> it = entries.iterator();
            
    if (it.hasNext()) {
                Map.Entry
    <K, ValueEntry> valueEntry = it.next();
                least 
    = valueEntry.getValue().count.get();
                toBeRemovedByCount 
    = valueEntry.getKey();
                earliest 
    = valueEntry.getValue().lastAccess.get();
                toBeRemovedByTime 
    = valueEntry.getKey();
            }
            
    while (it.hasNext()) {
                Map.Entry
    <K, ValueEntry> valueEntry = it.next();
                
    if (valueEntry.getValue().count.get() < least) {
                    least 
    = valueEntry.getValue().count.get();
                    toBeRemovedByCount 
    = valueEntry.getKey();
                }
                
    if (valueEntry.getValue().lastAccess.get() < earliest) {
                    earliest 
    = valueEntry.getValue().count.get();
                    toBeRemovedByTime 
    = valueEntry.getKey();
                }
            }
            
    // System.out.println("remove:" + toBeRemoved);
            
    // 如果最少使用次數(shù)大于MINI_ACCESS,那么移除訪問時間最早的項(xiàng)(也就是最久沒有被訪問的項(xiàng))
            if (least > MINI_ACCESS) {
                map.remove(toBeRemovedByTime);
            } 
    else {
                map.remove(toBeRemovedByCount);
            }
        }

        
    public V get(K key) {
            
    try {
                readLock.lock();
                V value 
    = null;
                ValueEntry valueEntry 
    = map.get(key);
                
    if (valueEntry != null) {
                    
    // 更新訪問時間戳
                    valueEntry.updateLastAccess();
                    
    // 更新訪問次數(shù)
                    valueEntry.count.incrementAndGet();
                    value 
    = valueEntry.value;
                }
                
    return value;
            } 
    finally {
                readLock.unlock();
            }
        }

        
    public void clear() {
            
    try {
                writeLock.lock();
                map.clear();
            } 
    finally {
                writeLock.unlock();
            }
        }

        
    public int size() {
            
    try {
                readLock.lock();
                
    return map.size();
            } 
    finally {
                readLock.unlock();
            }
        }

        
    public long getCount(K key) {
            
    try {
                readLock.lock();
                ValueEntry valueEntry 
    = map.get(key);
                
    if (valueEntry != null) {
                    
    return valueEntry.count.get();
                }
                
    return 0;
            } 
    finally {
                readLock.unlock();
            }
        }

        
    public Collection<Map.Entry<K, V>> getAll() {
            
    try {
                readLock.lock();
                Set
    <K> keys = map.keySet();
                Map
    <K, V> tmp = new HashMap<K, V>();
                
    for (K key : keys) {
                    tmp.put(key, map.get(key).value);
                }
                
    return new ArrayList<Map.Entry<K, V>>(tmp.entrySet());
            } 
    finally {
                readLock.unlock();
            }
        }

        
    class ValueEntry implements Serializable {
            
    private V value;

            
    private AtomicLong count;

            
    private AtomicLong lastAccess;

            
    public ValueEntry(V value) {
                
    this.value = value;
                
    this.count = new AtomicLong(0);
                lastAccess 
    = new AtomicLong(System.nanoTime());
            }

            
    public void updateLastAccess() {
                
    this.lastAccess.set(System.nanoTime());
            }

        }
    }




    評論

    # re: 簡單LRU算法實(shí)現(xiàn)緩存-update1  回復(fù)  更多評論   

    2007-09-30 10:04 by sitinspring
    Mark.

    # re: 簡單LRU算法實(shí)現(xiàn)緩存-update1  回復(fù)  更多評論   

    2007-10-13 03:07 by 小飛飛
    這個怎么用了?

    # re: 簡單LRU算法實(shí)現(xiàn)緩存-update1  回復(fù)  更多評論   

    2007-10-13 16:43 by dennis
    @小飛飛
    怎么用?老大,緩存怎么用

    # re: 簡單LRU算法實(shí)現(xiàn)緩存-update1  回復(fù)  更多評論   

    2008-01-09 13:57 by zhangwei
    很好,我正想找一個這樣的程序那,謝謝了。

    # re: 簡單LRU算法實(shí)現(xiàn)緩存-update1[未登錄]  回復(fù)  更多評論   

    2008-01-14 09:18 by bruce
    說一下咱用呀?樓主
    主站蜘蛛池模板: 亚洲欧洲日产国码久在线观看 | 亚洲黄色三级网站| 性短视频在线观看免费不卡流畅| 亚洲av午夜电影在线观看| 亚洲人成色77777| 无码中文在线二区免费| 成人网站免费大全日韩国产| 亚洲中文字幕久久精品无码2021| 亚洲精品岛国片在线观看| 国产成人精品免费视频大| 四虎影视久久久免费观看| 亚洲精品视频在线观看免费| 四虎永久免费观看| 亚洲免费在线视频观看| 色爽黄1000部免费软件下载| 亚洲欧洲精品一区二区三区| 亚洲国产精品自产在线播放| 我们的2018在线观看免费高清| fc2成年免费共享视频网站| 亚洲精品人成网在线播放影院 | 高潮内射免费看片| 亚洲伦理一二三四| 亚洲国产精品久久久天堂| 国产无遮挡吃胸膜奶免费看视频| 色猫咪免费人成网站在线观看| 黄色a级免费网站| 亚洲欧洲无码一区二区三区| 久久综合九九亚洲一区| 亚洲日韩国产精品乱| 在线观看成人免费视频| 亚洲免费在线视频播放| 午夜影院免费观看| 中文字幕免费在线视频| 天堂亚洲免费视频| 国产亚洲精品美女久久久久| 在线观看亚洲AV日韩A∨| 亚洲综合无码一区二区三区| 亚洲AV无码成人精品区天堂| 丁香五月亚洲综合深深爱| 亚洲 另类 无码 在线| 国产成人免费网站在线观看|