
∙1 Cache类
∙2 CacheManager类
∙1 Cache类
∙2 CacheManager类
∙
JAVA缓存有两种:
一、文件缓存,是指把数据存储在磁盘上,可以XML格式,也可以序列化文件DAT格式还是其它文件格式。
二、内存缓存,也就是实现一个类中静态Map,对这个Map进行常规的增删查。
其代码如下:
JAVA缓存 - Cache类
public class Cache {
private String key;//缓存ID
private Object value;//缓存数据
private long timeOut;//更新时间
private boolean expired; //是否终止
public Cache() {
super();
}
public Cache(String key, Object value, long timeOut, boolean expired) {
this.key = key;
this.value = value;
this.timeOut = timeOut;
this.expired = expired;
}
public String getKey() {
return key;
}
public long getTimeOut() {
return timeOut;
}
public Object getValue() {
return value;
}
public void setKey(String string) {
key = string;
}
public void setTimeOut(long l) {
timeOut = l;
}
public void setValue(Object object) {
value = object;
}
public booleanisExpired() {
return expired;
}
public void setExpired(boolean b) {
expired = b;
}
}
//测试类,
class Test {
public static void main(String[] args) {
System.out.println(CacheManager.getSimpleFlag("alksd"));
// CacheManager.putCache("abc", new Cache());
// CacheManager.putCache("def", new Cache());
// CacheManager.putCache("ccc", new Cache());
// CacheManager.clearOnly("");
// Cache c = new Cache();
// for (int i = 0; i < 10; i++) {
// CacheManager.putCache("" + i, c);
// }
// CacheManager.putCache("aaaaaaaa", c);
// CacheManager.putCache("abchcy;alskd", c);
// CacheManager.putCache("cccccccc", c);
// CacheManager.putCache("abcoqiwhcy", c);
// System.out.println("删除前的大小:"+CacheManager.getCacheSize());
// CacheManager.getCacheAllkey();
// CacheManager.clearAll("aaaa");
// System.out.println("删除后的大小:"+CacheManager.getCacheSize());
// CacheManager.getCacheAllkey();
}
}
JAVA缓存 - CacheManager类
public class CacheManager {
private static HashMapcacheMap = new HashMap();
//单实例构造方法
private CacheManager() {
super();
}
//获取布尔值的缓存
public static booleangetSimpleFlag(String key){
try{
return (Boolean) cacheMap.get(key);
}catch(NullPointerException e){
return false;
}
}
public static long getServerStartdt(String key){
try {
return (Long)cacheMap.get(key);
} catch (Exception ex) {
return 0;
}
}
//设置布尔值的缓存
public synchronized static booleansetSimpleFlag(String key,boolean flag){
if (flag &&getSimpleFlag(key)) {//假如为真不允许被覆盖
return false;
}else{
cacheMap.put(key, flag);
return true;
}
}
public synchronized static booleansetSimpleFlag(String key,longserverbegrundt){
if (cacheMap.get(key) == null) {
cacheMap.put(key,serverbegrundt);
return true;
}else{
return false;
}
}
//得到缓存。同步静态方法
private synchronized static Cache getCache(String key) {
return (Cache) cacheMap.get(key);
}
//判断是否存在一个缓存
private synchronized static booleanhasCache(String key) {
return cacheMap.containsKey(key);
}
//清除所有缓存
public synchronized static void clearAll() {
cacheMap.clear();
}
//清除某一类特定缓存,通过遍历HASHMAP下的所有对象,来判断它的KEY与传入的TYPE是否匹配
public synchronized static void clearAll(String type) {
Iterator i = cacheMap.entrySet().iterator();
String key;
ArrayListarr = new ArrayList();
try {
while (i.hasNext()) {
java.util.Map.Entry entry = (java.util.Map.Entry) i.next();
key = (String) entry.getKey();
if (key.startsWith(type)) { //如果匹配则删除掉
arr.add(key);
}
}
for (int k = 0; k } } catch (Exception ex) { ex.printStackTrace(); } } //清除指定的缓存 public synchronized static void clearOnly(String key) { cacheMap.remove(key); } //载入缓存 public synchronized static void putCache(String key, Cache obj) { cacheMap.put(key, obj); } //获取缓存信息 public static Cache getCacheInfo(String key) { if (hasCache(key)) { Cache cache = getCache(key); if (cacheExpired(cache)) { //调用判断是否终止方法 cache.setExpired(true); } return cache; }else return null; } //载入缓存信息 public static void putCacheInfo(String key, Cache obj, long dt,boolean expired) { Cache cache = new Cache(); cache.setKey(key); cache.setTimeOut(dt + System.currentTimeMillis()); //设置多久后更新缓存 cache.setValue(obj); cache.setExpired(expired); //缓存默认载入时,终止状态为FALSE cacheMap.put(key, cache); } //重写载入缓存信息方法 public static void putCacheInfo(String key,Cacheobj,longdt){ Cache cache = new Cache(); cache.setKey(key); cache.setTimeOut(dt+System.currentTimeMillis()); cache.setValue(obj); cache.setExpired(false); cacheMap.put(key,cache); } //判断缓存是否终止 public static booleancacheExpired(Cache cache) { if (null == cache) { //传入的缓存不存在 return false; } long nowDt = System.currentTimeMillis(); //系统当前的毫秒数 long cacheDt = cache.getTimeOut(); //缓存内的过期毫秒数 if (cacheDt<= 0||cacheDt>nowDt) { //过期时间小于等于零时,或者过期时间大于当前时间时,则为FALSE return false; } else { //大于过期时间 即过期 return true; } } //获取缓存中的大小 public static intgetCacheSize() { return cacheMap.size(); } //获取指定的类型的大小 public static intgetCacheSize(String type) { int k = 0; Iterator i = cacheMap.entrySet().iterator(); String key; try { while (i.hasNext()) { java.util.Map.Entry entry = (java.util.Map.Entry) i.next(); key = (String) entry.getKey(); if (key.indexOf(type) != -1) { //如果匹配则删除掉 k++; } } } catch (Exception ex) { ex.printStackTrace(); } return k; } //获取缓存对象中的所有键值名称 public static ArrayListgetCacheAllkey() { ArrayList a = new ArrayList(); try { Iterator i = cacheMap.entrySet().iterator(); while (i.hasNext()) { java.util.Map.Entry entry = (java.util.Map.Entry) i.next(); a.add((String) entry.getKey()); } } catch (Exception ex) {} finally { return a; } } //获取缓存对象中指定类型 的键值名称 public static ArrayListgetCacheListkey(String type) { ArrayList a = new ArrayList(); String key; try { Iterator i = cacheMap.entrySet().iterator(); while (i.hasNext()) { java.util.Map.Entry entry = (java.util.Map.Entry) i.next(); key = (String) entry.getKey(); if (key.indexOf(type) != -1) { a.add(key); } } } catch (Exception ex) {} finally { return a; } } } 2007-09-29 简单LRU算法实现缓存 最简单的LRU算法实现,就是利用jdk的LinkedHashMap,覆写其中的removeEldestEntry(Map.Entry)方法即可,如下所示: java 代码 1.import java.util.ArrayList; 2.import java.util.Collection; 3.import java.util.LinkedHashMap; 4.import java.util.concurrent.locks.Lock; 5.import java.util.concurrent.locks.ReentrantLock; 6.import java.util.Map; 7. 8. 9./** 10. * 类说明:利用LinkedHashMap实现简单的缓存, 必须实现removeEldestEntry方法,具体参见JDK文档 11. * 12. * @author dennis 13. * 14. * @param 15. * @param 16. */ 17.public class LRULinkedHashMap 18. private final int maxCapacity; 19. 20. private static final float DEFAULT_LOAD_FACTOR = 0.75f; 21. 22. private final Lock lock = new ReentrantLock(); 23. 24. public LRULinkedHashMap(int maxCapacity) { 25. super(maxCapacity, DEFAULT_LOAD_FACTOR, true); 26. this.maxCapacity = maxCapacity; 27. } 28. 29. @Override 30. protected boolean removeEldestEntry(java.util.Map.Entry 31. return size() > maxCapacity; 32. } 33. @Override 34. public boolean containsKey(Object key) { 35. try { 36. lock.lock(); 37. return super.containsKey(key); 38. } finally { 39. lock.unlock(); 40. } 41. } 42. 43. 44. @Override 45. public V get(Object key) { 46. try { 47. lock.lock(); 48. return super.get(key); 49. } finally { 50. lock.unlock(); 51. } 52. } 53. 54. @Override 55. public V put(K key, V value) { 56. try { 57. lock.lock(); 58. return super.put(key, value); 59. } finally { 60. lock.unlock(); 61. } 62. } 63. . public int size() { 65. try { 66. lock.lock(); 67. return super.size(); 68. } finally { 69. lock.unlock(); 70. } 71. } 72. 73. public void clear() { 74. try { 75. lock.lock(); 76. super.clear(); 77. } finally { 78. lock.unlock(); 79. } 80. } 81. 82. public Collection 83. try { 84. lock.lock(); 85. return new ArrayList 86. } finally { 87. lock.unlock(); 88. } . } 90.} 91. 如果你去看LinkedHashMap的源码可知,LRU算法是通过双向链表来实现,当某个位置被命中,通过调整链表的指向将该位置调整到头位置,新加入的内容直接放在链表头,如此一来,最近被命中的内容就向链表头移动,需要替换时,链表最后的位置就是最近最少使用的位置。 LRU算法还可以通过计数来实现,缓存存储的位置附带一个计数器,当命中时将计数器加1,替换时就查找计数最小的位置并替换,结合访问时间戳来实现。这种算法比较适合缓存数据量较小的场景,显然,遍历查找计数最小位置的时间复杂度为O(n)。我实现了一个,结合了访问时间戳,当最小计数大于 MINI_ACESS时,就移除最久没有被访问的项: java 代码 1.import java.io.Serializable; 2.import java.util.ArrayList; 3.import java.util.Collection; 4.import java.util.HashMap; 5.import java.util.Iterator; 6.import java.util.Map; 7.import java.util.Set; 8.import java.util.concurrent.atomic.AtomicInteger; 9.import java.util.concurrent.atomic.AtomicLong; 10.import java.util.concurrent.locks.Lock; 11.import java.util.concurrent.locks.ReentrantLock; 12. 13./** 14. * 15. * @author dennis 16. * 类说明:当缓存数目不多时,才用缓存计数的传统LRU算法 17. * @param 18. * @param 19. */ 20.public class LRUCache 21. 22. private static final int DEFAULT_CAPACITY = 100; 23. 24. protected Map 25. 26. private final Lock lock = new ReentrantLock(); 27. 28. private final transient int maxCapacity; 29. 30. private static int MINI_ACCESS = 10; 31. 32. public LRUCache() { 33. this(DEFAULT_CAPACITY); 34. } 35. 36. public LRUCache(int capacity) { 37. if (capacity <= 0) 38. throw new RuntimeException("缓存容量不得小于0"); 39. this.maxCapacity = capacity; 40. this.map = new HashMap 41. } 42. 43. public boolean ContainsKey(K key) { 44. try { 45. lock.lock(); 46. return this.map.containsKey(key); 47. } finally { 48. lock.unlock(); 49. } 50. } 51. 52. public V put(K key, V value) { 53. try { 54. lock.lock(); 55. if ((map.size() > maxCapacity - 1) && !map.containsKey(key)) { 56. // System.out.println("开始"); 57. Set 58. removeRencentlyLeastAccess(entries); 59. } 60. ValueEntry valueEntry = map.put(key, new ValueEntry(value)); 61. if (valueEntry != null) 62. return valueEntry.value; 63. else . return null; 65. } finally { 66. lock.unlock(); 67. } 68. } 69. 70. /** 71. * 移除最近最少访问 72. */ 73. protected void removeRencentlyLeastAccess( 74. Set 75. // 最小使用次数 76. int least = 0; 77. // 最久没有被访问 78. long earliest = 0; 79. K toBeRemovedByCount = null; 80. K toBeRemovedByTime = null; 81. Iterator 82. if (it.hasNext()) { 83. Map.Entry 84. least = valueEntry.getValue().count.get(); 85. toBeRemovedByCount = valueEntry.getKey(); 86. earliest = valueEntry.getValue().lastAccess.get(); 87. toBeRemovedByTime = valueEntry.getKey(); 88. } . while (it.hasNext()) { 90. Map.Entry 91. if (valueEntry.getValue().count.get() < least) { 92. least = valueEntry.getValue().count.get(); 93. toBeRemovedByCount = valueEntry.getKey(); 94. } 95. if (valueEntry.getValue().lastAccess.get() < earliest) { 96. earliest = valueEntry.getValue().count.get(); 97. toBeRemovedByTime = valueEntry.getKey(); 98. } 99. } 100. // System.out.println("remove:" + toBeRemoved); 101. // 如果最少使用次数大于MINI_ACCESS,那么移除访问时间最早的项(也就是最久没有被访问的项) 102. if (least > MINI_ACCESS) { 103. map.remove(toBeRemovedByTime); 104. } else { 105. map.remove(toBeRemovedByCount); 106. } 107. } 108. 109. public V get(K key) { 110. try { 111. lock.lock(); 112. V value = null; 113. ValueEntry valueEntry = map.get(key); 114. if (valueEntry != null) { 115. // 更新访问时间戳 116. valueEntry.updateLastAccess(); 117. // 更新访问次数 118. valueEntry.count.incrementAndGet(); 119. value = valueEntry.value; 120. } 121. return value; 122. } finally { 123. lock.unlock(); 124. } 125. } 126. 127. public void clear() { 128. try { 129. lock.lock(); 130. map.clear(); 131. } finally { 132. lock.unlock(); 133. } 134. } 135. 136. public int size() { 137. try { 138. lock.lock(); 139. return map.size(); 140. } finally { 141. lock.unlock(); 142. } 143. } 144. 145. public Collection 146. try { 147. lock.lock(); 148. Set 149. Map 150. for (K key : keys) { 151. tmp.put(key, map.get(key).value); 152. } 153. return new ArrayList 154. } finally { 155. lock.unlock(); 156. } 157. } 158. 159. class ValueEntry implements Serializable { 160. private V value; 161. 162. private AtomicInteger count; 163. 1. private AtomicLong lastAccess; 165. 166. public ValueEntry(V value) { 167. this.value = value; 168. this.count = new AtomicInteger(0); 169. lastAccess = new AtomicLong(System.nanoTime()); 170. } 171. 172. public void updateLastAccess() { 173. this.lastAccess.set(System.nanoTime()); 174. } 175. 176. } 177.} 2008-04-07 LRU Cache 看了下RU(Least Recently Used ,最近最少使用),可以使用LinkedHashMap实现,到是蛮简单的.LinkedHashMap会将get或是put的数据置于底端. 重写removeEldestEntry()可以设定根据size来调整cache的数量. Java代码 1.import java.util.Collection; 2.import java.util.LinkedHashMap; 3.import java.util.Map; 4. 5./** 6. * This class uses the LinkedHashMap to build LRU cache. 7. * User can define the cache size. 8. */ 9.public class LRUCache 10.{ 11. int cacheSize = 0; 12. float loadFactor = 0.75f; //default 13. LinkedHashMap map; 14. 15. public LRUCache(int cacheSize) 16. { 17. this.cacheSize = cacheSize; 18. map = new LinkedHashMap(cacheSize, loadFactor, true) 19. { 20. protected boolean removeEldestEntry(Map.Entry eldest) 21. { 22. return size() > LRUCache.this.cacheSize; 23. //return false; 24. } 25. }; 26. } 27. 28. public synchronized void clear() 29. { 30. map.clear(); 31. } 32. 33. public synchronized Object get(Object key) 34. { 35. return map.get(key); 36. } 37. 38. public synchronized void put(Object key, Object value) 39. { 40. map.put( 41. key, 42. value); 43. } 44. 45. public synchronized Object remove(Object key) 46. { 47. return map.remove(key); 48. } 49. 50. public synchronized int size() 51. { 52. return map.size(); 53. } 54. 55. public synchronized Collection values() 56. { 57. return map.values(); 58. } 59. 60. public static void main(String []args) 61. { 62. // testing 63. int size = 3; . LRUCache cache = new LRUCache(size); 65. cache.put(new Integer("1"), "1"); 66. cache.put(new Integer("2"), "2"); 67. cache.put(new Integer("3"), "3"); 68. 69. String value = (String)cache.get(new Integer(1)); 70. System.out.println(value); 71. System.out.println("Testing ..."); 72. 73. Object[] values = cache.values().toArray(); 74. for (int i = 0; i < values.length; i++) 75. { 76. value = (String)values[i]; 77. System.out.println(value); 78. } 79. } 80.} LRU缓存应用一例 《基于双链表实现缓存策略之LRU实现》,正好站内有一个搜索 《ACM AND JAVA》http://www.java3z.com/cwbwebhome/acm.jsp 需要缓存,应用了一把,这样就不需要每次搜索POJID都查询数据库。先凑合着用了。 package com.db; import java.util.Hashtable; importjava.sql.*; public class LRUCache { private intcacheSize; private Hashtable nodes;//缓存容器 private intcurrentSize; private CacheNode first;//链表头 private CacheNode last;//链表尾 private static LRUCache instance=new LRUCache(1000); /** * 链表节点 * @author Administrator * */ class CacheNode { CacheNodeprev;//前一节点 CacheNode next;//后一节点 Object value;//值 Object key;//键 CacheNode() { } } private LRUCache(int i) { currentSize = 0; cacheSize = i; nodes = new Hashtable(i);//缓存容器 ResultSetRst=null; DbTransdb=new DbTrans(); try{ Rst=db.executeQuery("select File_name,Article_type from Article where type_id=17"); String f_name=null; String a_type=null; while(Rst.next()){//将数据库中的记录全部取出,缓存。 a_type=Rst.getString("Article_type"); f_name=Rst.getString("File_name"); put(a_type,f_name); } if(Rst!=null) Rst.close(); if(db!=null) db.close(); }catch(SQLException e){ System.out.println(e.toString()); } } public static LRUCachegetInstance(){ return instance; } /** * 获取缓存中对象 * @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; } } 有些不满意之处,主要是缓存大小不好确定,暂定为1000, 以后题目多了,要重新编译源文件。(缓存大小最好写在一个配置 文件中) 最后看一下JSP文件:POJsearch.jsp,从提交页面获取POJID,从缓存中取数据。 <%@ page import="com.db.LRUCache" %> <%@ page import="java.util.regex.Matcher" %> <%@ page import="java.util.regex.Pattern" %> <%@ page import="com.db.LRUCache" %> <% String s=request.getParameter("s"); String toPage="nothing.jsp"; String pattern = "\\\\d{1,5}"; out.println(s); if(s==null||s.length()==0) { toPage="nothing.jsp"; }else { Pattern p = Pattern.compile(pattern); Matcher m = p.matcher(s); boolean b = m.matches(); out.println(b); if(!b){ toPage="nothing.jsp"; }else{ LRUCache cache=LRUCache.getInstance(); String f_name=(String)cache.get(s); if(f_name!=null) toPage=f_name; else toPage="nothing.jsp"; } } response.sendRedirect(toPage); %> 首先,来看看LRU的定义: Least recently used. 可以理解为,最少使用的被淘汰。在网上发现了这个LRUCache 类及文章
