最近项目要引入缓存机制,但是不想引入分布式的缓存框架,所以自己就写了一个轻量级的缓存实现,有两个版本,一个是通过timer实现其超时过期处理,另外一个是通过list轮询。
       首先要了解下java1.6中的ConcurrentMap ,他是一个线程安全的Map实现,特别说明的是在没有特别需求的情况下可以用ConcurrentHashMap。我是想学习一下读写锁的应用,就自己实现了一个SimpleConcurrentHashMap.

  1. package com.cttc.cache.entity;
  2. import java.util.ArrayList;
  3. import java.util.Collection;
  4. import java.util.HashSet;
  5. import java.util.Map;
  6. import java.util.Set;
  7. import java.util.concurrent.locks.Lock;
  8. import java.util.concurrent.locks.ReadWriteLock;
  9. import java.util.concurrent.locks.ReentrantReadWriteLock;
  10. public class SimpleConcurrentMap<K, V> implements Map<K, V> {
  11. final ReadWriteLock lock = new ReentrantReadWriteLock();
  12. final Lock r = lock.readLock();
  13. final Lock w = lock.writeLock();
  14. final Map<K, V> map;
  15. public SimpleConcurrentMap(Map<K, V> map) {
  16. this.map = map;
  17. if (map == null) throw new NullPointerException();
  18. }
  19. public void clear() {
  20. w.lock();
  21. try {
  22. map.clear();
  23. } finally {
  24. w.unlock();
  25. }
  26. }
  27. public boolean containsKey(Object key) {
  28. r.lock();
  29. try {
  30. return map.containsKey(key);
  31. } finally {
  32. r.unlock();
  33. }
  34. }
  35. public boolean containsValue(Object value) {
  36. r.lock();
  37. try {
  38. return map.containsValue(value);
  39. } finally {
  40. r.unlock();
  41. }
  42. }
  43. public Set<java.util.Map.Entry<K, V>> entrySet() {
  44. throw new UnsupportedOperationException();
  45. }
  46. public V get(Object key) {
  47. r.lock();
  48. try {
  49. return map.get(key);
  50. } finally {
  51. r.unlock();
  52. }
  53. }
  54. public boolean isEmpty() {
  55. r.lock();
  56. try {
  57. return map.isEmpty();
  58. } finally {
  59. r.unlock();
  60. }
  61. }
  62. public Set<K> keySet() {
  63. r.lock();
  64. try {
  65. return new HashSet<K>(map.keySet());
  66. } finally {
  67. r.unlock();
  68. }
  69. }
  70. public V put(K key, V value) {
  71. w.lock();
  72. try {
  73. return map.put(key, value);
  74. } finally {
  75. w.unlock();
  76. }
  77. }
  78. public void putAll(Map<? extends K, ? extends V> m) {
  79. w.lock();
  80. try {
  81. map.putAll(m);
  82. } finally {
  83. w.unlock();
  84. }
  85. }
  86. public V remove(Object key) {
  87. w.lock();
  88. try {
  89. return map.remove(key);
  90. } finally {
  91. w.unlock();
  92. }
  93. }
  94. public int size() {
  95. r.lock();
  96. try {
  97. return map.size();
  98. } finally {
  99. r.unlock();
  100. }
  101. }
  102. public Collection<V> values() {
  103. r.lock();
  104. try {
  105. return new ArrayList<V>(map.values());
  106. } finally {
  107. r.unlock();
  108. }
  109. }
  110. }

缓存对象CacheEntity.Java为:

  1. package com.cttc.cache.entity;
  2. import java.io.Serializable;
  3. public class CacheEntity implements Serializable{
  4. private static final long serialVersionUID = -3971709196436977492L;
  5. private final int DEFUALT_VALIDITY_TIME = 20;//默认过期时间 20秒
  6. private String cacheKey;
  7. private Object cacheContext;
  8. private int validityTime;//有效期时长,单位:秒
  9. private long timeoutStamp;//过期时间戳
  10. private CacheEntity(){
  11. this.timeoutStamp = System.currentTimeMillis() + DEFUALT_VALIDITY_TIME * 1000;
  12. this.validityTime = DEFUALT_VALIDITY_TIME;
  13. }
  14. public CacheEntity(String cacheKey, Object cacheContext){
  15. this();
  16. this.cacheKey = cacheKey;
  17. this.cacheContext = cacheContext;
  18. }
  19. public CacheEntity(String cacheKey, Object cacheContext, long timeoutStamp){
  20. this(cacheKey, cacheContext);
  21. this.timeoutStamp = timeoutStamp;
  22. }
  23. public CacheEntity(String cacheKey, Object cacheContext, int validityTime){
  24. this(cacheKey, cacheContext);
  25. this.validityTime = validityTime;
  26. this.timeoutStamp = System.currentTimeMillis() + validityTime * 1000;
  27. }
  28. public String getCacheKey() {
  29. return cacheKey;
  30. }
  31. public void setCacheKey(String cacheKey) {
  32. this.cacheKey = cacheKey;
  33. }
  34. public Object getCacheContext() {
  35. return cacheContext;
  36. }
  37. public void setCacheContext(Object cacheContext) {
  38. this.cacheContext = cacheContext;
  39. }
  40. public long getTimeoutStamp() {
  41. return timeoutStamp;
  42. }
  43. public void setTimeoutStamp(long timeoutStamp) {
  44. this.timeoutStamp = timeoutStamp;
  45. }
  46. public int getValidityTime() {
  47. return validityTime;
  48. }
  49. public void setValidityTime(int validityTime) {
  50. this.validityTime = validityTime;
  51. }
  52. }

List缓存处理对象:

  1. package com.cttc.cache.handler;
  2. import java.util.ArrayList;
  3. import java.util.HashMap;
  4. import java.util.List;
  5. import com.cttc.cache.entity.CacheEntity;
  6. import com.cttc.cache.entity.SimpleConcurrentMap;
  7. /**
  8. * @projName:WZServer
  9. * @className:CacheHandler
  10. * @description:缓存操作类,对缓存进行管理,采用处理队列,定时循环清理的方式
  11. * @creater:Administrator
  12. * @creatTime:2013年7月22日 上午9:18:54
  13. * @alter:Administrator
  14. * @alterTime:2013年7月22日 上午9:18:54
  15. * @remark:
  16. * @version
  17. */
  18. public class CacheListHandler {
  19. private static final long SECOND_TIME = 1000;
  20. private static final SimpleConcurrentMap<String, CacheEntity> map;
  21. private static final List<CacheEntity> tempList;
  22. static{
  23. tempList = new ArrayList<CacheEntity>();
  24. map = new SimpleConcurrentMap<String, CacheEntity>(new HashMap<String, CacheEntity>(1<<18));
  25. new Thread(new TimeoutTimerThread()).start();
  26. }
  27. /**
  28. * 增加缓存对象
  29. * @param key
  30. * @param ce
  31. */
  32. public static void addCache(String key, CacheEntity ce){
  33. addCache(key, ce, ce.getValidityTime());
  34. }
  35. /**
  36. * 增加缓存对象
  37. * @param key
  38. * @param ce
  39. * @param validityTime 有效时间
  40. */
  41. public static synchronized void addCache(String key, CacheEntity ce, int validityTime){
  42. ce.setTimeoutStamp(System.currentTimeMillis() + validityTime * SECOND_TIME);
  43. map.put(key, ce);
  44. //添加到过期处理队列
  45. tempList.add(ce);
  46. }
  47. /**
  48. * 获取缓存对象
  49. * @param key
  50. * @return
  51. */
  52. public static synchronized CacheEntity getCache(String key){
  53. return map.get(key);
  54. }
  55. /**
  56. * 检查是否含有制定key的缓冲
  57. * @param key
  58. * @return
  59. */
  60. public static synchronized boolean isConcurrent(String key){
  61. return map.containsKey(key);
  62. }
  63. /**
  64. * 删除缓存
  65. * @param key
  66. */
  67. public static synchronized void removeCache(String key){
  68. map.remove(key);
  69. }
  70. /**
  71. * 获取缓存大小
  72. * @param key
  73. */
  74. public static int getCacheSize(){
  75. return map.size();
  76. }
  77. /**
  78. * 清除全部缓存
  79. */
  80. public static synchronized void clearCache(){
  81. tempList.clear();
  82. map.clear();
  83. System.out.println("clear cache");
  84. }
  85. static class TimeoutTimerThread implements Runnable {
  86. public void run(){
  87. while(true){
  88. try {
  89. checkTime();
  90. } catch (Exception e) {
  91. e.printStackTrace();
  92. }
  93. }
  94. }
  95. /**
  96. * 过期缓存的具体处理方法
  97. * @throws Exception
  98. */
  99. private void checkTime() throws Exception{
  100. //"开始处理过期 ";
  101. CacheEntity tce = null;
  102. long timoutTime = 1000L;
  103. //" 过期队列大小 : "+tempList.size());
  104. if(1 > tempList.size()){
  105. System.out.println("过期队列空,开始轮询");
  106. timoutTime = 1000L;
  107. Thread.sleep(timoutTime);
  108. return;
  109. }
  110. tce = tempList.get(0);
  111. timoutTime = tce.getTimeoutStamp() - System.currentTimeMillis();
  112. //" 过期时间 : "+timoutTime);
  113. if(0 < timoutTime){
  114. //设定过期时间
  115. Thread.sleep(timoutTime);
  116. return;
  117. }
  118. System.out.print(" 清除过期缓存 : "+tce.getCacheKey());
  119. //清除过期缓存和删除对应的缓存队列
  120. tempList.remove(tce);
  121. removeCache(tce.getCacheKey());
  122. }
  123. }
  124. }

Timer方式

  1. package com.cttc.cache.handler;
  2. import java.util.HashMap;
  3. import java.util.Timer;
  4. import java.util.TimerTask;
  5. import com.cttc.cache.entity.CacheEntity;
  6. import com.cttc.cache.entity.SimpleConcurrentMap;
  7. /**
  8. * @projName:WZServer
  9. * @className:CacheHandler
  10. * @description:缓存操作类,对缓存进行管理,清除方式采用Timer定时的方式
  11. * @creater:Administrator
  12. * @creatTime:2013年7月22日 上午9:18:54
  13. * @alter:Administrator
  14. * @alterTime:2013年7月22日 上午9:18:54
  15. * @remark:
  16. * @version
  17. */
  18. public class CacheTimerHandler {
  19. private static final long SECOND_TIME = 1000;//默认过期时间 20秒
  20. private static final int DEFUALT_VALIDITY_TIME = 20;//默认过期时间 20秒
  21. private static final Timer timer ;
  22. private static final SimpleConcurrentMap<String, CacheEntity> map;
  23. static{
  24. timer = new Timer();
  25. map = new SimpleConcurrentMap<String, CacheEntity>(new HashMap<String, CacheEntity>(1<<18));
  26. }
  27. /**
  28. * 增加缓存对象
  29. * @param key
  30. * @param ce
  31. */
  32. public static void addCache(String key, CacheEntity ce){
  33. addCache(key, ce, DEFUALT_VALIDITY_TIME);
  34. }
  35. /**
  36. * 增加缓存对象
  37. * @param key
  38. * @param ce
  39. * @param validityTime 有效时间
  40. */
  41. public static synchronized void addCache(String key, CacheEntity ce, int validityTime){
  42. map.put(key, ce);
  43. //添加过期定时
  44. timer.schedule(new TimeoutTimerTask(key), validityTime * SECOND_TIME);
  45. }
  46. /**
  47. * 获取缓存对象
  48. * @param key
  49. * @return
  50. */
  51. public static synchronized CacheEntity getCache(String key){
  52. return map.get(key);
  53. }
  54. /**
  55. * 检查是否含有制定key的缓冲
  56. * @param key
  57. * @return
  58. */
  59. public static synchronized boolean isConcurrent(String key){
  60. return map.containsKey(key);
  61. }
  62. /**
  63. * 删除缓存
  64. * @param key
  65. */
  66. public static synchronized void removeCache(String key){
  67. map.remove(key);
  68. }
  69. /**
  70. * 获取缓存大小
  71. * @param key
  72. */
  73. public static int getCacheSize(){
  74. return map.size();
  75. }
  76. /**
  77. * 清除全部缓存
  78. */
  79. public static synchronized void clearCache(){
  80. if(null != timer){
  81. timer.cancel();
  82. }
  83. map.clear();
  84. System.out.println("clear cache");
  85. }
  86. /**
  87. * @projName:WZServer
  88. * @className:TimeoutTimerTask
  89. * @description:清除超时缓存定时服务类
  90. * @creater:Administrator
  91. * @creatTime:2013年7月22日 上午9:34:39
  92. * @alter:Administrator
  93. * @alterTime:2013年7月22日 上午9:34:39
  94. * @remark:
  95. * @version
  96. */
  97. static class TimeoutTimerTask extends TimerTask{
  98. private String ceKey ;
  99. public TimeoutTimerTask(String key){
  100. this.ceKey = key;
  101. }
  102. @Override
  103. public void run() {
  104. CacheTimerHandler.removeCache(ceKey);
  105. System.out.println("remove : "+ceKey);
  106. }
  107. }
  108. }

timer方式有点是适用性更强,因为每个缓存的过期时间都可以独立配置的;ist只能适用于缓存时间都一样的线性过期。从性能开销方面,因为timer是与缓存对象数量成正比的,在缓存量很大的时候,在缓存时间内系统开销也随之提高;而list方式只要一个线程管理过期清理就可以了。

这里要感谢饭饭泛,从其微博学习到很多http://www.blogjava.net/xylz/archive/2010/07/14/326080.html

对timer方式的改进,定时程序只需要一个就可以了,过期时间,通过一个对象保存,根据每个对象的过期时间判断是否移除该缓存。于是得到下面的版本:

package com.cttc.cache.handler;

import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
/**
* 在缓存的时候,同时记录下该key,缓存时间,失效周期
* 在读取缓存的时候,更新该key的缓存时间,
* 定时器每两个小时运行一次,检查每个key是否过期,如果过期,删除Jboss中的cache
*
*/
public class CacheTimerMamager{
private static final long SECOND_TIME = 1000;//毫秒
private static final long DEFUALT_VALIDITY_TIME = SECOND_TIME * 60 * 60 * 2;//默认过期时间 :2小时
private static final Timer timer ;
private static final Map<String, CacheOutTime> map; static{
timer = new Timer();
map = new HashMap<String, CacheOutTime>();
timer.schedule(new CacheTimerTask(), DEFUALT_VALIDITY_TIME, DEFUALT_VALIDITY_TIME);
} /**
* 增加缓存对象
* @param key
* @param ce
*/
public static synchronized void addCache(String key){
CacheOutTime cot = map.get(key);
long outTime = System.currentTimeMillis()+DEFUALT_VALIDITY_TIME;
if(cot==null){
cot = new CacheOutTime(key, outTime);
map.put(key, cot);
}else{
//更新该key的过期时间
cot.setTimeoutStamp(outTime);
}
} //移除cache
/**
* 考虑,在多线程时,当有线程已经取得缓存对象时,删掉了缓存,会产生什么情况
*/
public static synchronized void removeCache() {
CacheOutTime cot;
long currentTime = System.currentTimeMillis();
for (String key : map.keySet()) {
cot = map.get(key);
if(cot.getTimeoutStamp()<=currentTime){
System.out.println("remove : "+key);
}
}
}
static class CacheTimerTask extends TimerTask{
@Override
public void run() {
//移除cache
CacheTimerMamager.removeCache();
}
} } class CacheOutTime {
private String cacheKey;
private long timeoutStamp;//过期时间戳,在最后一次访问该key的时候计算得到 public CacheOutTime() {
super();
}
public CacheOutTime(String cacheKey, long timeoutStamp) {
super();
this.cacheKey = cacheKey;
this.timeoutStamp = timeoutStamp;
} public String getCacheKey() {
return cacheKey;
}
public void setCacheKey(String cacheKey) {
this.cacheKey = cacheKey;
}
public long getTimeoutStamp() {
return timeoutStamp;
}
public void setTimeoutStamp(long timeoutStamp) {
this.timeoutStamp = timeoutStamp;
}
}

  

package com.cttc.cache.handler;
import java.util.HashMap;import java.util.Map;import java.util.Timer;import java.util.TimerTask;/** * 在缓存的时候,同时记录下该key,缓存时间,失效周期 * 在读取缓存的时候,更新该key的缓存时间, * 定时器每两个小时运行一次,检查每个key是否过期,如果过期,删除Jboss中的cache * */public class CacheTimerMamager{private static final long SECOND_TIME = 1000;//毫秒private static final long DEFUALT_VALIDITY_TIME = SECOND_TIME * 60 * 60 * 2;//默认过期时间 :2小时private static final Timer timer ;private static final Map<String, CacheOutTime> map;static{timer = new Timer();map = new HashMap<String, CacheOutTime>();timer.schedule(new CacheTimerTask(), DEFUALT_VALIDITY_TIME, DEFUALT_VALIDITY_TIME);}/** * 增加缓存对象 * @param key * @param ce */public static synchronized void  addCache(String key){CacheOutTime cot = map.get(key);long outTime = System.currentTimeMillis()+DEFUALT_VALIDITY_TIME;if(cot==null){cot = new CacheOutTime(key, outTime);map.put(key, cot);}else{//更新该key的过期时间cot.setTimeoutStamp(outTime);}}//移除cache/** * 考虑,在多线程时,当有线程已经取得缓存对象时,删掉了缓存,会产生什么情况 */public static synchronized void removeCache() {CacheOutTime cot;long currentTime = System.currentTimeMillis();for (String key : map.keySet()) {cot = map.get(key);if(cot.getTimeoutStamp()<=currentTime){System.out.println("remove : "+key);}}}static class CacheTimerTask extends TimerTask{@Overridepublic void run() {//移除cacheCacheTimerMamager.removeCache();}}}
class CacheOutTime {private String cacheKey;private long timeoutStamp;//过期时间戳,在最后一次访问该key的时候计算得到public CacheOutTime() {super();}public CacheOutTime(String cacheKey, long timeoutStamp) {super();this.cacheKey = cacheKey;this.timeoutStamp = timeoutStamp;}public String getCacheKey() {return cacheKey;}public void setCacheKey(String cacheKey) {this.cacheKey = cacheKey;}public long getTimeoutStamp() {return timeoutStamp;}public void setTimeoutStamp(long timeoutStamp) {this.timeoutStamp = timeoutStamp;}}

java cache过期策略两种实现,一个基于list轮询一个基于timer定时的更多相关文章

  1. ASP.NET缓存中Cache过期的三种策略

    原文:ASP.NET缓存中Cache过期的三种策略 我们在页面上添加三个按钮并双击按钮创建事件处理方法,三个按钮使用不同的过期策略添加ASP.NET缓存. <asp:Button ID=&quo ...

  2. 从上面的集合框架图可以看到,Java 集合框架主要包括两种类型的容器,一种是集合(Collection),存储一个元素集合,另一种是图(Map),存储键/值对映射

    从上面的集合框架图可以看到,Java 集合框架主要包括两种类型的容器,一种是集合(Collection),存储一个元素集合,另一种是图(Map),存储键/值对映射.Collection 接口又有 3 ...

  3. 对Java代码加密的两种方式,防止反编译

    使用Virbox Protector对Java项目加密有两种方式,一种是对War包加密,一种是对Jar包加密.Virbox Protector支持这两种文件格式加密,可以加密用于解析class文件的j ...

  4. Java新建线程的两种方式

    Java新建线程有两种方式,一种是通过继承Thread类,一种是实现Runnable接口,下面是新建线程的两种方式. 我们假设有个竞赛,有一个选手A做俯卧撑,一个选手B做仰卧起坐.分别为两个线程: p ...

  5. 【转载】JAVA中线程的两种实现方法-实现Runnable接口和继承Thread类

    转自: http://blog.csdn.net/sunguangran/article/details/6069317 非常感谢原作者,整理的这么详细. 在java中可有两种方式实现多线程,一种是继 ...

  6. java中线程分两种,守护线程和用户线程。

    java中线程分为两种类型:用户线程和守护线程. 通过Thread.setDaemon(false)设置为用户线程: 通过Thread.setDaemon(true)设置为守护线程. 如果不设置次属性 ...

  7. Java线程创建的两种方式

    java多线程总结一:线程的两种创建方式及优劣比较 (一)---之创建线程的两种方式 java实现多线程的两种方法的比较

  8. iOS 两种不同的图片无限轮播

    代码地址如下:http://www.demodashi.com/demo/11608.html 前记 其实想写这个关于无限轮播的记录已经很久很久了,只是没什么时间,这只是一个借口,正如:时间就像海绵, ...

  9. WebSocket实践——Java实现WebSocket的两种方式

    什么是 WebSocket? 随着互联网的发展,传统的HTTP协议已经很难满足Web应用日益复杂的需求了.近年来,随着HTML5的诞生,WebSocket协议被提出,它实现了浏览器与服务器的全双工通信 ...

随机推荐

  1. TF/IDF(term frequency/inverse document frequency)

    TF/IDF(term frequency/inverse document frequency) 的概念被公认为信息检索中最重要的发明. 一. TF/IDF描述单个term与特定document的相 ...

  2. Careercup - Google面试题 - 5724823657381888

    2014-05-06 06:37 题目链接 原题: Given an array of (unsorted) integers, arrange them such that a < b > ...

  3. android开发 两张bitmap图片合成一张图片

    场景:对android4.4解码gif(解码文章见前面一篇)后的图片进行每帧处理,android4.3 解码出来的每帧都很完整,但是到android4.4版本就不完整了,每帧都是在第一帧的基础上把被改 ...

  4. Netsharp FAQ

    1.启动服务器时候不能监听端口,出现如下错误: 回答: 这种问题应该是在win7环境下才有,是没有权限,要以管理员身份运行Netsharp.Elephant.Q.exe. 2.启动服务器的时候,服务端 ...

  5. Java 7 中 NIO.2 的使用——第四节 文件和目录

    Files类提供了很多方法用于检查在于你真正实际去操作一个文件或目录.这些方法强烈推荐,也非常有用,也能避免很多异常的发生.例如,一个很好的习惯就是在你试着移动一个文件从一个地方到另一个地方的时候,先 ...

  6. python 网络编程-TCP/UDP

    摘抄自:廖雪峰的官方网站:http://www.liaoxuefeng.com/ TCP客户端和服务器端代码: #coding=utf-8 #客户端程序TCP 连接 import socket s=s ...

  7. 【Python】内置数据类型

    参考资料: http://sebug.net/paper/books/dive-into-python3/native-datatypes.html http://blog.csdn.net/hazi ...

  8. 【BZOJ】【3157】&【BZOJ】【3516】国王奇遇记

    数论 题解:http://www.cnblogs.com/zhuohan123/p/3726933.html copy一下推导过程: 令$$S_i=\sum_{k=1}^{n}k^im^k$$ 我们有 ...

  9. 【BZOJ】【3280】小R的烦恼

    网络流/费用流 和软件开发那题基本相同,只是多加了一个“雇佣研究生”的限制:不同价格的研究生有不同的数量…… 那么只需加一个附加源点,对每一种研究生连边 S->ss 容量为l[i],费用为p[i ...

  10. Matlab实现单变量线性回归

    一.理论 二.数据集 6.1101,17.592 5.5277,9.1302 8.5186,13.662 7.0032,11.854 5.8598,6.8233 8.3829,11.886 7.476 ...