lru repost

Simple

LRU algorithm
to
    implement caching ;  import java.util.Collection;  import java.util.LinkedHashMap;  import java.util.concurrent.locks.Lock;  import java.util.concurrent.locks.ReentrantLock;  import java.util.Map;  /** * class description : Use LinkedHashMap to implement simple caching, you must implement the removeEldestEntry method, see JDK documentation for details * @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(); 
        } 
    } 

   

  If you look at the source code of LinkedHashMap, you can see that the LRU algorithm is implemented through a doubly linked list. When a position is hit, the position is adjusted to the head position by adjusting the pointer of the linked list, and the newly added content is directly placed at the head of the linked list. , the most recently hit content is moved to the head of the linked list. When it needs to be replaced, the last position of the linked list is the least recently used position.
    The LRU algorithm can also be implemented by counting. A counter is attached to the cache storage location. When a hit occurs, the counter is incremented by 1. When replacing, the location with the smallest count is found and replaced, combined with the access timestamp. This algorithm is more suitable for scenarios with a small amount of cached data. Obviously, the time complexity of traversing and finding the position with the smallest count is O(n). I implemented one, combined with the access timestamp, when the minimum count is greater than MINI_ACESS, remove the item that has not been accessed for the longest time:
java code

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.ReentrantLock; 
 
/**

* @author dennis 
* Class description: When the number of caches is small, the traditional LRU algorithm of cache count is used
* @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 Lock lock = new ReentrantLock(); 
 
    private final transient int maxCapacity; 
 
    private static int MINI_ACCESS = 10; 
 
    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 { 
            lock.lock(); 
            return this.map.containsKey(key); 
        } finally { 
            lock.unlock(); 
        } 
    } 
 
    public V put(K key, V value) { 
        try { 
            lock.lock(); 
            if ((map.size() > maxCapacity - 1) && !map.containsKey(key)) { 
                // System.out.println("开始"); 
                Set<Map.Entry<K, ValueEntry>> entries = this.map.entrySet(); 
                removeRencentlyLeastAccess(entries); 
            } 
            ValueEntry valueEntry = map.put(key, new ValueEntry(value)); 
            if (valueEntry != null) 
                return valueEntry.value; 
            else 
                return null; 
        } finally { 
            lock.unlock(); 
        } 
    } 
 
    /**
     * 移除最近最少访问
     */ 
    protected void removeRencentlyLeastAccess( 
            Set<Map.Entry<K, ValueEntry>> entries) { 
        // 最小使用次数 
        int 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); 
        // if If the minimum number of times of use is greater than MINI_ACCESS, then remove the item with the earliest access time (that is, the item that has not been accessed for the longest time) 
        if (least > MINI_ACCESS) { 
            map.remove(toBeRemovedByTime); 
        } else { 
            map.remove(toBeRemovedByCount); 
        } 
    } 
 
    public V get(K key) { 
        try { 
            lock.lock(); 
            V value = null; 
            ValueEntry valueEntry = map.get(key); 
            if (valueEntry != null) { 
                // 更新访问时间戳 
                valueEntry.updateLastAccess(); 
                // 更新访问次数 
                valueEntry.count.incrementAndGet(); 
                value = valueEntry.value; 
            } 
            return value; 
        } finally { 
            lock.unlock(); 
        } 
    } 
 
    public void clear() { 
        try { 
            lock.lock(); 
            map.clear(); 
        } finally { 
            lock.unlock(); 
        } 
    } 
 
    public int size() { 
        try { 
            lock.lock(); 
            return map.size(); 
        } finally { 
            lock.unlock(); 
        } 
    } 
 
    public Collection<Map.Entry<K, V>> getAll() { 
        try { 
            lock.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 { 
            lock.unlock(); 
        } 
    } 
 
    class ValueEntry implements Serializable { 
        private V value; 
 
        private AtomicInteger count; 
 
        private AtomicLong lastAccess; 
 
        public ValueEntry(V value) { 
            this.value = value; 
            this.count = new AtomicInteger(0); 
            lastAccess = new AtomicLong(System.nanoTime()); 
        } 
         
        public void updateLastAccess() { 
            this.lastAccess.set(System.nanoTime()); 
        } 
 
    } 

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326986955&siteId=291194637
LRU