缓存 LRU- java的版本
来源:互联网 发布:算法研发工程师 编辑:程序博客网 时间:2024/04/29 14:50
一、使用LinkedHashMap实现
//Copyright 2007 Christian d'Heureuse, Inventec Informatik AG, Zurich, Switzerland
//www.source-code.biz, www.inventec.ch/chdh
//
//This module is multi-licensed and may be used under the terms
//of any of the following licenses:
//
//EPL, Eclipse Public License, V1.0 or later, http://www.eclipse.org/legal
//LGPL, GNU Lesser General Public License, V2 or later, http://www.gnu.org/licenses/lgpl.html
//GPL, GNU General Public License, V2 or later, http://www.gnu.org/licenses/gpl.html
//AL, Apache License, V2.0 or later, http://www.apache.org/licenses
//BSD, BSD License, http://www.opensource.org/licenses/bsd-license.php
//
//Please contact the author if you need another license.
//This module is provided "as is", without warranties of any kind.
/**
* LinkedHashMap。 用这个类有两大好处:
* 一是它本身已经实现了按照访问顺序的存储,也就是说,最近读取的会放在最前面,最最不常读取的会放在最后
* (当然,它也可以实现按照插入顺序存储)。
* 第二,LinkedHashMap本身有一个方法用于判断是否需要移除最不常读取的数,但是,原始方法默认不需要移除
* (这是,LinkedHashMap相当于一个linkedlist),
* 所以,我们需要override这样一个方法,使得当缓存里存放的数据个数超过规定个数后,就把最不常用的移除掉。
*/
import java.util.LinkedHashMap;
import java.util.Collection;
import java.util.Map;
import java.util.ArrayList;
/**
* An LRU cache, based on <code>LinkedHashMap</code>.
*
* <p>
* This cache has a fixed maximum number of elements (<code>cacheSize</code>).
* If the cache is full and another entry is added, the LRU (least recently used) entry is dropped.
*
* <p>
* This class is thread-safe. All methods of this class are synchronized.
*
* <p>
* Author: Christian d'Heureuse, Inventec Informatik AG, Zurich, Switzerland<br>
* Multi-licensed: EPL / LGPL / GPL / AL / BSD.
*/
public class LRUCache<K,V> {
private static final float hashTableLoadFactor = 0.75f;
private LinkedHashMap<K,V> map;
private int cacheSize;
/**
* Creates a new LRU cache.
* @param cacheSize the maximum number of entries that will be kept in this cache.
*/
public LRUCache (int cacheSize) {
this.cacheSize = cacheSize;
int hashTableCapacity = (int)Math.ceil(cacheSize / hashTableLoadFactor) + 1;
map = new LinkedHashMap<K,V>(hashTableCapacity, hashTableLoadFactor, true) {
// (an anonymous inner class)
private static final long serialVersionUID = 1;
@Override protected boolean removeEldestEntry (Map.Entry<K,V> eldest) {
return size() > LRUCache.this.cacheSize;
}
};
}
/**
* Retrieves an entry from the cache.<br>
* The retrieved entry becomes the MRU (most recently used) entry.
* @param key the key whose associated value is to be returned.
* @return the value associated to this key, or null if no value with this key exists in the cache.
*/
public synchronized V get (K key) {
return map.get(key);
}
/**
* Adds an entry to this cache.
* The new entry becomes the MRU (most recently used) entry.
* If an entry with the specified key already exists in the cache, it is replaced by the new entry.
* If the cache is full, the LRU (least recently used) entry is removed from the cache.
* @param key the key with which the specified value is to be associated.
* @param value a value to be associated with the specified key.
*/
public synchronized void put (K key, V value) {
map.put (key, value);
}
/**
* Clears the cache.
*/
public synchronized void clear() {
map.clear();
}
/**
* Returns the number of used entries in the cache.
* @return the number of entries currently in the cache.
*/
public synchronized int usedEntries() {
return map.size();
}
/**
* Returns a <code>Collection</code> that contains a copy of all cache entries.
* @return a <code>Collection</code> with a copy of the cache content.
*/
public synchronized Collection<Map.Entry<K,V>> getAll() {
return new ArrayList<Map.Entry<K,V>>(map.entrySet());
}
} // end class LRUCache
或直接使用(推荐上面的方式,上面的方法更优雅一些)
//Copyright 2007 Christian d'Heureuse, Inventec Informatik AG, Zurich, Switzerland
//www.source-code.biz, www.inventec.ch/chdh
//
//This module is multi-licensed and may be used under the terms
//of any of the following licenses:
//
//EPL, Eclipse Public License, V1.0 or later, http://www.eclipse.org/legal
//LGPL, GNU Lesser General Public License, V2 or later, http://www.gnu.org/licenses/lgpl.html
//GPL, GNU General Public License, V2 or later, http://www.gnu.org/licenses/gpl.html
//AL, Apache License, V2.0 or later, http://www.apache.org/licenses
//BSD, BSD License, http://www.opensource.org/licenses/bsd-license.php
//
//Please contact the author if you need another license.
//This module is provided "as is", without warranties of any kind.
/**
* LinkedHashMap。 用这个类有两大好处:
* 一是它本身已经实现了按照访问顺序的存储,也就是说,最近读取的会放在最前面,最最不常读取的会放在最后
* (当然,它也可以实现按照插入顺序存储)。
* 第二,LinkedHashMap本身有一个方法用于判断是否需要移除最不常读取的数,但是,原始方法默认不需要移除
* (这是,LinkedHashMap相当于一个linkedlist),
* 所以,我们需要override这样一个方法,使得当缓存里存放的数据个数超过规定个数后,就把最不常用的移除掉。
*/
import java.util.LinkedHashMap;
import java.util.Collection;
import java.util.Map;
import java.util.ArrayList;
/**
* An LRU cache, based on <code>LinkedHashMap</code>.
*
* <p>
* This cache has a fixed maximum number of elements (<code>cacheSize</code>).
* If the cache is full and another entry is added, the LRU (least recently used) entry is dropped.
*
* <p>
* This class is thread-safe. All methods of this class are synchronized.
*
* <p>
* Author: Christian d'Heureuse, Inventec Informatik AG, Zurich, Switzerland<br>
* Multi-licensed: EPL / LGPL / GPL / AL / BSD.
*/
public class LRUCache<K,V> {
private static final float hashTableLoadFactor = 0.75f;
private LinkedHashMap<K,V> map;
private int cacheSize;
/**
* Creates a new LRU cache.
* @param cacheSize the maximum number of entries that will be kept in this cache.
*/
public LRUCache (int cacheSize) {
this.cacheSize = cacheSize;
int hashTableCapacity = (int)Math.ceil(cacheSize / hashTableLoadFactor) + 1;
map = new LinkedHashMap<K,V>(hashTableCapacity, hashTableLoadFactor, true) {
// (an anonymous inner class)
private static final long serialVersionUID = 1;
@Override protected boolean removeEldestEntry (Map.Entry<K,V> eldest) {
return size() > LRUCache.this.cacheSize;
}
};
}
/**
* Retrieves an entry from the cache.<br>
* The retrieved entry becomes the MRU (most recently used) entry.
* @param key the key whose associated value is to be returned.
* @return the value associated to this key, or null if no value with this key exists in the cache.
*/
public synchronized V get (K key) {
return map.get(key);
}
/**
* Adds an entry to this cache.
* The new entry becomes the MRU (most recently used) entry.
* If an entry with the specified key already exists in the cache, it is replaced by the new entry.
* If the cache is full, the LRU (least recently used) entry is removed from the cache.
* @param key the key with which the specified value is to be associated.
* @param value a value to be associated with the specified key.
*/
public synchronized void put (K key, V value) {
map.put (key, value);
}
/**
* Clears the cache.
*/
public synchronized void clear() {
map.clear();
}
/**
* Returns the number of used entries in the cache.
* @return the number of entries currently in the cache.
*/
public synchronized int usedEntries() {
return map.size();
}
/**
* Returns a <code>Collection</code> that contains a copy of all cache entries.
* @return a <code>Collection</code> with a copy of the cache content.
*/
public synchronized Collection<Map.Entry<K,V>> getAll() {
return new ArrayList<Map.Entry<K,V>>(map.entrySet());
}
} // end class LRUCache
final int cacheSize = 100;
Map<String, String> map = new LinkedHashMap<String, String>((int) Math.ceil(cacheSize / 0.75f) + 1, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<String, String> eldest) {
return size() > cacheSize;
}
};
java源码分析之LinkedHashMap参考 : http://blog.csdn.net/jzhf2012/article/details/8540688
二、基于双链表的LRU算法的实现(tomcat6之前版本用到的org.apache.tomcat.util.collections.LRUCache)
- public class LRUCache {
- /**
- * 链表节点
- * @author Administrator
- *
- */
- class CacheNode {
- CacheNode prev;//前一节点
- CacheNode next;//后一节点
- Object value;//值
- Object key;//键
- CacheNode() {
- }
- }
- public LRUCache(int i) {
- currentSize = 0;
- cacheSize = i;
- nodes = new Hashtable(i);//缓存容器
- }
- /**
- * 获取缓存中对象
- * @param key
- * @return
- */
- public Object get(Object key) {
- CacheNode node = (CacheNode) nodes.get(key);
- if (node != null) {
- moveToHead(node);
- return node.value;
- } else {
- return null;
- }
- }
- /**
- * 添加缓存
- * @param key
- * @param value
- */
- public void put(Object key, Object value) {
- CacheNode node = (CacheNode) nodes.get(key);
- if (node == null) {
- //缓存容器是否已经超过大小.
- if (currentSize >= cacheSize) {
- if (last != null)//将最少使用的删除
- nodes.remove(last.key);
- removeLast();
- } else {
- currentSize++;
- }
- node = new CacheNode();
- }
- node.value = value;
- node.key = key;
- //将最新使用的节点放到链表头,表示最新使用的.
- moveToHead(node);
- nodes.put(key, node);
- }
- /**
- * 将缓存删除
- * @param key
- * @return
- */
- public Object remove(Object key) {
- CacheNode node = (CacheNode) nodes.get(key);
- if (node != null) {
- if (node.prev != null) {
- node.prev.next = node.next;
- }
- if (node.next != null) {
- node.next.prev = node.prev;
- }
- if (last == node)
- last = node.prev;
- if (first == node)
- first = node.next;
- }
- return node;
- }
- public void clear() {
- first = null;
- last = null;
- }
- /**
- * 删除链表尾部节点
- * 表示 删除最少使用的缓存对象
- */
- private void removeLast() {
- //链表尾不为空,则将链表尾指向null. 删除连表尾(删除最少使用的缓存对象)
- if (last != null) {
- if (last.prev != null)
- last.prev.next = null;
- else
- first = null;
- last = last.prev;
- }
- }
- /**
- * 移动到链表头,表示这个节点是最新使用过的
- * @param node
- */
- private void moveToHead(CacheNode node) {
- if (node == first)
- return;
- if (node.prev != null)
- node.prev.next = node.next;
- if (node.next != null)
- node.next.prev = node.prev;
- if (last == node)
- last = node.prev;
- if (first != null) {
- node.next = first;
- first.prev = node;
- }
- first = node;
- node.prev = null;
- if (last == null)
- last = first;
- }
- private int cacheSize;
- private Hashtable nodes;//缓存容器
- private int currentSize;
- private CacheNode first;//链表头
- private CacheNode last;//链表尾
- }
加锁的 一种写法:
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.Map.Entry;
- import java.util.Set;
- import java.util.concurrent.atomic.AtomicLong;
- import java.util.concurrent.locks.Lock;
- import java.util.concurrent.locks.ReadWriteLock;
- import java.util.concurrent.locks.ReentrantReadWriteLock;
- /**
- *
- * 类说明:当缓存数目不多时,才用缓存计数的传统LRU算法
- *
- * @param
- * @param
- */
- public class LRUCache<K, V> implements Serializable {
- /**
- *
- */
- private static final long serialVersionUID = 2727577376847051556L;
- 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 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<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 V removeRencentlyLeastAccess(Set<Map.Entry<K, ValueEntry>> entries) {
- // 最小使用次数
- 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);
- // 如果最少使用次数大于MINI_ACCESS,那么移除访问时间最早的项(也就是最久没有被访问的项)
- if (least > MINI_ACCESS) {
- return map.remove(toBeRemovedByTime).value;
- } else {
- return map.remove(toBeRemovedByCount).value;
- }
- }
- public V get(K key) {
- try {
- readLock.lock();
- V value = null;
- ValueEntry valueEntry = map.get(key);
- if (valueEntry != null) {
- // 更新访问时间戳
- valueEntry.updateLastAccess();
- // 更新访问次数
- 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<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<Entry<K, V>>(tmp.entrySet());
- } finally {
- readLock.unlock();
- }
- }
- class ValueEntry implements Serializable {
- /**
- *
- */
- private static final long serialVersionUID = -7626403101359191860L;
- 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());
- }
- }
- }
参考:http://www.cnblogs.com/lzrabbit/p/3734850.html
0 0
- 缓存 LRU- java的版本
- LRU缓存的java实现
- LRU缓存实现(Java)
- LRU缓存实现(Java)
- LRU缓存实现(Java)
- LRU缓存实现(Java)
- LRU缓存实现(Java)
- LRU缓存实现(Java)
- LRU缓存实现(Java)
- LRU缓存实现(Java)
- LRU缓存实现(Java)
- Java实现LRU缓存
- LRU缓存实现(Java)
- LRU缓存实现(Java)
- Java实现LRU缓存
- LRU缓存实现(Java)
- LRU缓存实现(Java)
- LRU缓存实现(Java)
- 分治法的经典问题
- H264基础概念
- 子类继承父类,重写纯虚函数和虚函数时注意
- HDU ACM 4143 A Simple Problem
- p122 6
- 缓存 LRU- java的版本
- Java与C++人气出现历史新低?程序员们不必太过惊慌
- 定制iOS 7中的导航栏和状态栏
- Windows命令行命令详解
- Oracle Study之--DBCA建库错误(AMD CPU)
- 第三章习题
- JAVA关键字—final修饰符
- Linux常用命令-文件处理命令-目录处理命令
- CentOS 7安装过程中遇到的问题总结