【搬砖-3】本地缓存

缓存算法

1. LRU(Least Recently Used)

每次访问就把这个元素放到队列头部,队列满了淘汰队列尾的元素,也就是淘汰最长时间没有被访问的。

缺点:某一时刻大量数据的到来容易把热点数据挤出缓存,而这些数据却是只访问了一次的,今后不会再访问了的或者访问频率极低的。

java实现——LinkedHashMap

public class LRULinkedMap<K, V> {
    
    
 
	/**
     * 最大缓存大小
     */
	private int cacheSize;
	
	private LinkedHashMap<K, V> cacheMap;
	
	public LRULinkedMap(int cacheSize){
    
    
		this.cacheSize = cacheSize;
		
		cacheMap = new LinkedHashMap(16, 0.75F, true){
    
    
 
			@Override
			protected boolean removeEldestEntry(Entry eldest) {
    
    
				if(cacheSize + 1 == cacheMap.size()){
    
    
					return true;
				}else{
    
    
					return false;
				}
			}
		};
	}
	
	public void put(K key, V value){
    
    
		cacheMap.put(key, value);
	}
	
	public V get(K key){
    
    
		return cacheMap.get(key);
	}
	
	public Collection<Map.Entry<K, V>> getAll(){
    
    
		return new ArrayList<Map.Entry<K, V>>(cacheMap.entrySet());
	}
		
}
	 

java实现——双向链表+hashMap
  • 原理
    这篇文章非常形象生动了,不啰嗦了:https://www.jianshu.com/p/74a4efacb0a7
  • java实现
  1. 定义双向链表
class LRUNode {
    
    
    Object key;
    Object value;
    LRUNode prev;
    LRUNode next;
    public LRUNode(Object key, Object value) {
    
    
        this.key = key;
        this.value = value;
    }
}
  1. 实现缓存功能
class LRUCache{
    
    
	private LRUNode head;
	private LRUNode tail;
	private final int capacity = 3;
	HashMap<K, V> map = new HashMap<>();
	public void set(K key, V value) {
    
    
        LRUNode node = map.get(key);
        if (node != null) {
    
    
            node = map.get(key);
            node.value = value;
            remove(node, false);
        } else {
    
    
            node = new LRUNode(key, value);
            if (map.size() >= capacity) {
    
    
                // 每次容量不足时先删除最久未使用的元素
                remove(tail, true);
            }
            map.put(key, node);
        }
        // 将刚添加的元素设置为head
        setHead(node);
    }
    public Object get(K key) {
    
    
        LRUNode node = map.get(key);
        if (node != null) {
    
    
            // 将刚操作的元素放到head
            remove(node, false);
            setHead(node);
            return node.value;
        }
        return null;
    }
    private void setHead(LRUNode node) {
    
    
        // 先从链表中删除该元素
        if (head != null) {
    
    
            node.next = head;
            head.prev = node;
        }
        head = node;
        if (tail == null) {
    
    
            tail = node;
        }
    }
    // 从链表中删除此Node,此时要注意该Node是head或者是tail的情形
    private void remove(LRUNode node, boolean flag) {
    
    
        if (node.prev != null) {
    
    
            node.prev.next = node.next;
        } else {
    
    
            head = node.next;
        }
        if (node.next != null) {
    
    
            node.next.prev = node.prev;
        } else {
    
    
            tail = node.prev;
        }
        node.next = null;
        node.prev = null;
        if (flag) {
    
    
            map.remove(node.key);
        }
    }
}
2. LFU(Least Frequently Used)

淘汰一定时期内被访问次数最少的元素。如果元素的一定时间内的访问次数相同时,则比较他们的最新一次的访问时间

public class LFUAgingMap<K, V> extends HashMap<K, V> {
    
    
    private static final int DEFAULT_MAX_SIZE = 3;
    private int maxSize = DEFAULT_MAX_SIZE;
    Map<K, HitRate> km = new HashMap<K, HitRate>();

    public LFUAgingMap() {
    
    
        this(DEFAULT_MAX_SIZE);
    }

    public LFUAgingMap(int maxSize) {
    
    
        super(maxSize);
        this.maxSize = maxSize;
    }

    @Override
    public V get(Object key) {
    
    
        V v = super.get(key);
        if (v != null) {
    
    
            HitRate hitRate = km.get(key);
            hitRate.hitCount += 1;
            hitRate.atime = System.nanoTime();
        }
        return v;
    }

    @Override
    public V put(K key, V value) {
    
    
        while (km.size() >= maxSize) {
    
    
            K k = getLFUAging();
            km.remove(k);
            this.remove(k);
        }
        V v = super.put(key, value);
        km.put(key, new HitRate(key, 1, System.nanoTime()));
        return v;
    }

    private K getLFUAging() {
    
    
        HitRate min = Collections.min(km.values());
        return min.key;
    }
	// HitRate 命中率
    class HitRate implements Comparable<HitRate> {
    
    
        K key;
        Integer hitCount; // 命中次数
        Long atime; // 上次命中时间

        public HitRate(K key, Integer hitCount, Long atime) {
    
    
            this.key = key;
            this.hitCount = hitCount;
            this.atime = atime;
        }

        @Override
        public int compareTo(HitRate o) {
    
    
            int hr = hitCount.compareTo(o.hitCount);
            return hr != 0 ? hr : atime.compareTo(o.atime);
        }
    }
}

Guava

原理后续学习

Caffeine

原理后续学习

猜你喜欢

转载自blog.csdn.net/u010659877/article/details/105324444
今日推荐