package com.taobao.tddl.common.utils;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap;
import com.googlecode.concurrentlinkedhashmap.EvictionListener;
import com.googlecode.concurrentlinkedhashmap.Weighers;
/**
* 基于google concurrent的LinkedHashMap实现LRU cache
*
* @author jianghang 2013-10-23 下午5:02:50
* @since 5.0.0
*/
public class GoogleConcurrentLruCache<K, V> {
private ConcurrentLinkedHashMap<K, V> cache;
private static final int DEFAULT_CAPACITY = 389;
public static final int DEFAULT_CONCURENCY_LEVEL = 64;
private AtomicLong get = new AtomicLong(0);
private AtomicLong hit = new AtomicLong(0);
public GoogleConcurrentLruCache(){
this(DEFAULT_CAPACITY);
}
public GoogleConcurrentLruCache(int capacity){
if (capacity <= 0) {
capacity = DEFAULT_CAPACITY;
}
cache = new ConcurrentLinkedHashMap.Builder<K, V>().maximumWeightedCapacity(capacity)
.weigher(Weighers.singleton())
.concurrencyLevel(DEFAULT_CONCURENCY_LEVEL)
.build();
}
public GoogleConcurrentLruCache(int capacity, EvictionListener<K, V> listener){
if (capacity <= 0) {
capacity = DEFAULT_CAPACITY;
}
cache = new ConcurrentLinkedHashMap.Builder<K, V>().maximumWeightedCapacity(capacity)
.weigher(Weighers.singleton())
.concurrencyLevel(DEFAULT_CONCURENCY_LEVEL)
.listener(listener)
.build();
}
public long capacity() {
return cache.capacity();
}
public boolean isEmpty() {
return cache.isEmpty();
}
public int size() {
return cache.size();
}
public void clear() {
cache.clear();
}
public V get(Object key) {
V v = cache.get(key);
get.addAndGet(1);
if (v != null) {
hit.addAndGet(1);
}
return v;
}
public void put(K key, V value) {
cache.put(key, value);
}
public boolean putIfAbsent(K key, V value) {
return cache.putIfAbsent(key, value) == null;
}
public boolean replace(K key, V old, V value) {
return cache.replace(key, old, value);
}
public void remove(K key) {
cache.remove(key);
}
public Set<K> keySet() {
return cache.keySet();
}
public Set<K> hotKeySet(int n) {
return cache.descendingKeySetWithLimit(n);
}
public boolean containsKey(K key) {
return cache.containsKey(key);
}
public String getStatus() {
StringBuilder sb = new StringBuilder();
sb.append("current size:");
sb.append(cache.size());
sb.append(" get:");
sb.append(get);
sb.append(" hit:");
sb.append(hit);
sb.append(" hit ratio:");
if (get.longValue() > 0) {
sb.append((hit.doubleValue() / get.doubleValue()) * 100);
sb.append("%");
} else {
sb.append("--");
}
get.set(0);
hit.set(0);
return sb.toString();
}
}