java cache过期策略两种实现,一个基于list轮询一个基于timer定时
最近项目要引入缓存机制,但是不想引入分布式的缓存框架,所以自己就写了一个轻量级的缓存实现,有两个版本,一个是通过timer实现其超时过期处理,另外一个是通过list轮询。
首先要了解下java1.6中的ConcurrentMap ,他是一个线程安全的Map实现,特别说明的是在没有特别需求的情况下可以用ConcurrentHashMap。我是想学习一下读写锁的应用,就自己实现了一个SimpleConcurrentHashMap.
- package com.cttc.cache.entity;
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.HashSet;
- import java.util.Map;
- import java.util.Set;
- import java.util.concurrent.locks.Lock;
- import java.util.concurrent.locks.ReadWriteLock;
- import java.util.concurrent.locks.ReentrantReadWriteLock;
- public class SimpleConcurrentMap<K, V> implements Map<K, V> {
- final ReadWriteLock lock = new ReentrantReadWriteLock();
- final Lock r = lock.readLock();
- final Lock w = lock.writeLock();
- final Map<K, V> map;
- public SimpleConcurrentMap(Map<K, V> map) {
- this.map = map;
- if (map == null) throw new NullPointerException();
- }
- public void clear() {
- w.lock();
- try {
- map.clear();
- } finally {
- w.unlock();
- }
- }
- public boolean containsKey(Object key) {
- r.lock();
- try {
- return map.containsKey(key);
- } finally {
- r.unlock();
- }
- }
- public boolean containsValue(Object value) {
- r.lock();
- try {
- return map.containsValue(value);
- } finally {
- r.unlock();
- }
- }
- public Set<java.util.Map.Entry<K, V>> entrySet() {
- throw new UnsupportedOperationException();
- }
- public V get(Object key) {
- r.lock();
- try {
- return map.get(key);
- } finally {
- r.unlock();
- }
- }
- public boolean isEmpty() {
- r.lock();
- try {
- return map.isEmpty();
- } finally {
- r.unlock();
- }
- }
- public Set<K> keySet() {
- r.lock();
- try {
- return new HashSet<K>(map.keySet());
- } finally {
- r.unlock();
- }
- }
- public V put(K key, V value) {
- w.lock();
- try {
- return map.put(key, value);
- } finally {
- w.unlock();
- }
- }
- public void putAll(Map<? extends K, ? extends V> m) {
- w.lock();
- try {
- map.putAll(m);
- } finally {
- w.unlock();
- }
- }
- public V remove(Object key) {
- w.lock();
- try {
- return map.remove(key);
- } finally {
- w.unlock();
- }
- }
- public int size() {
- r.lock();
- try {
- return map.size();
- } finally {
- r.unlock();
- }
- }
- public Collection<V> values() {
- r.lock();
- try {
- return new ArrayList<V>(map.values());
- } finally {
- r.unlock();
- }
- }
- }
缓存对象CacheEntity.Java为:
- package com.cttc.cache.entity;
- import java.io.Serializable;
- public class CacheEntity implements Serializable{
- private static final long serialVersionUID = -3971709196436977492L;
- private final int DEFUALT_VALIDITY_TIME = 20;//默认过期时间 20秒
- private String cacheKey;
- private Object cacheContext;
- private int validityTime;//有效期时长,单位:秒
- private long timeoutStamp;//过期时间戳
- private CacheEntity(){
- this.timeoutStamp = System.currentTimeMillis() + DEFUALT_VALIDITY_TIME * 1000;
- this.validityTime = DEFUALT_VALIDITY_TIME;
- }
- public CacheEntity(String cacheKey, Object cacheContext){
- this();
- this.cacheKey = cacheKey;
- this.cacheContext = cacheContext;
- }
- public CacheEntity(String cacheKey, Object cacheContext, long timeoutStamp){
- this(cacheKey, cacheContext);
- this.timeoutStamp = timeoutStamp;
- }
- public CacheEntity(String cacheKey, Object cacheContext, int validityTime){
- this(cacheKey, cacheContext);
- this.validityTime = validityTime;
- this.timeoutStamp = System.currentTimeMillis() + validityTime * 1000;
- }
- public String getCacheKey() {
- return cacheKey;
- }
- public void setCacheKey(String cacheKey) {
- this.cacheKey = cacheKey;
- }
- public Object getCacheContext() {
- return cacheContext;
- }
- public void setCacheContext(Object cacheContext) {
- this.cacheContext = cacheContext;
- }
- public long getTimeoutStamp() {
- return timeoutStamp;
- }
- public void setTimeoutStamp(long timeoutStamp) {
- this.timeoutStamp = timeoutStamp;
- }
- public int getValidityTime() {
- return validityTime;
- }
- public void setValidityTime(int validityTime) {
- this.validityTime = validityTime;
- }
- }
List缓存处理对象:
- package com.cttc.cache.handler;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.List;
- import com.cttc.cache.entity.CacheEntity;
- import com.cttc.cache.entity.SimpleConcurrentMap;
- /**
- * @projName:WZServer
- * @className:CacheHandler
- * @description:缓存操作类,对缓存进行管理,采用处理队列,定时循环清理的方式
- * @creater:Administrator
- * @creatTime:2013年7月22日 上午9:18:54
- * @alter:Administrator
- * @alterTime:2013年7月22日 上午9:18:54
- * @remark:
- * @version
- */
- public class CacheListHandler {
- private static final long SECOND_TIME = 1000;
- private static final SimpleConcurrentMap<String, CacheEntity> map;
- private static final List<CacheEntity> tempList;
- static{
- tempList = new ArrayList<CacheEntity>();
- map = new SimpleConcurrentMap<String, CacheEntity>(new HashMap<String, CacheEntity>(1<<18));
- new Thread(new TimeoutTimerThread()).start();
- }
- /**
- * 增加缓存对象
- * @param key
- * @param ce
- */
- public static void addCache(String key, CacheEntity ce){
- addCache(key, ce, ce.getValidityTime());
- }
- /**
- * 增加缓存对象
- * @param key
- * @param ce
- * @param validityTime 有效时间
- */
- public static synchronized void addCache(String key, CacheEntity ce, int validityTime){
- ce.setTimeoutStamp(System.currentTimeMillis() + validityTime * SECOND_TIME);
- map.put(key, ce);
- //添加到过期处理队列
- tempList.add(ce);
- }
- /**
- * 获取缓存对象
- * @param key
- * @return
- */
- public static synchronized CacheEntity getCache(String key){
- return map.get(key);
- }
- /**
- * 检查是否含有制定key的缓冲
- * @param key
- * @return
- */
- public static synchronized boolean isConcurrent(String key){
- return map.containsKey(key);
- }
- /**
- * 删除缓存
- * @param key
- */
- public static synchronized void removeCache(String key){
- map.remove(key);
- }
- /**
- * 获取缓存大小
- * @param key
- */
- public static int getCacheSize(){
- return map.size();
- }
- /**
- * 清除全部缓存
- */
- public static synchronized void clearCache(){
- tempList.clear();
- map.clear();
- System.out.println("clear cache");
- }
- static class TimeoutTimerThread implements Runnable {
- public void run(){
- while(true){
- try {
- checkTime();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- /**
- * 过期缓存的具体处理方法
- * @throws Exception
- */
- private void checkTime() throws Exception{
- //"开始处理过期 ";
- CacheEntity tce = null;
- long timoutTime = 1000L;
- //" 过期队列大小 : "+tempList.size());
- if(1 > tempList.size()){
- System.out.println("过期队列空,开始轮询");
- timoutTime = 1000L;
- Thread.sleep(timoutTime);
- return;
- }
- tce = tempList.get(0);
- timoutTime = tce.getTimeoutStamp() - System.currentTimeMillis();
- //" 过期时间 : "+timoutTime);
- if(0 < timoutTime){
- //设定过期时间
- Thread.sleep(timoutTime);
- return;
- }
- System.out.print(" 清除过期缓存 : "+tce.getCacheKey());
- //清除过期缓存和删除对应的缓存队列
- tempList.remove(tce);
- removeCache(tce.getCacheKey());
- }
- }
- }
Timer方式
- package com.cttc.cache.handler;
- import java.util.HashMap;
- import java.util.Timer;
- import java.util.TimerTask;
- import com.cttc.cache.entity.CacheEntity;
- import com.cttc.cache.entity.SimpleConcurrentMap;
- /**
- * @projName:WZServer
- * @className:CacheHandler
- * @description:缓存操作类,对缓存进行管理,清除方式采用Timer定时的方式
- * @creater:Administrator
- * @creatTime:2013年7月22日 上午9:18:54
- * @alter:Administrator
- * @alterTime:2013年7月22日 上午9:18:54
- * @remark:
- * @version
- */
- public class CacheTimerHandler {
- private static final long SECOND_TIME = 1000;//默认过期时间 20秒
- private static final int DEFUALT_VALIDITY_TIME = 20;//默认过期时间 20秒
- private static final Timer timer ;
- private static final SimpleConcurrentMap<String, CacheEntity> map;
- static{
- timer = new Timer();
- map = new SimpleConcurrentMap<String, CacheEntity>(new HashMap<String, CacheEntity>(1<<18));
- }
- /**
- * 增加缓存对象
- * @param key
- * @param ce
- */
- public static void addCache(String key, CacheEntity ce){
- addCache(key, ce, DEFUALT_VALIDITY_TIME);
- }
- /**
- * 增加缓存对象
- * @param key
- * @param ce
- * @param validityTime 有效时间
- */
- public static synchronized void addCache(String key, CacheEntity ce, int validityTime){
- map.put(key, ce);
- //添加过期定时
- timer.schedule(new TimeoutTimerTask(key), validityTime * SECOND_TIME);
- }
- /**
- * 获取缓存对象
- * @param key
- * @return
- */
- public static synchronized CacheEntity getCache(String key){
- return map.get(key);
- }
- /**
- * 检查是否含有制定key的缓冲
- * @param key
- * @return
- */
- public static synchronized boolean isConcurrent(String key){
- return map.containsKey(key);
- }
- /**
- * 删除缓存
- * @param key
- */
- public static synchronized void removeCache(String key){
- map.remove(key);
- }
- /**
- * 获取缓存大小
- * @param key
- */
- public static int getCacheSize(){
- return map.size();
- }
- /**
- * 清除全部缓存
- */
- public static synchronized void clearCache(){
- if(null != timer){
- timer.cancel();
- }
- map.clear();
- System.out.println("clear cache");
- }
- /**
- * @projName:WZServer
- * @className:TimeoutTimerTask
- * @description:清除超时缓存定时服务类
- * @creater:Administrator
- * @creatTime:2013年7月22日 上午9:34:39
- * @alter:Administrator
- * @alterTime:2013年7月22日 上午9:34:39
- * @remark:
- * @version
- */
- static class TimeoutTimerTask extends TimerTask{
- private String ceKey ;
- public TimeoutTimerTask(String key){
- this.ceKey = key;
- }
- @Override
- public void run() {
- CacheTimerHandler.removeCache(ceKey);
- System.out.println("remove : "+ceKey);
- }
- }
- }
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定时的更多相关文章
- ASP.NET缓存中Cache过期的三种策略
原文:ASP.NET缓存中Cache过期的三种策略 我们在页面上添加三个按钮并双击按钮创建事件处理方法,三个按钮使用不同的过期策略添加ASP.NET缓存. <asp:Button ID=&quo ...
- 从上面的集合框架图可以看到,Java 集合框架主要包括两种类型的容器,一种是集合(Collection),存储一个元素集合,另一种是图(Map),存储键/值对映射
从上面的集合框架图可以看到,Java 集合框架主要包括两种类型的容器,一种是集合(Collection),存储一个元素集合,另一种是图(Map),存储键/值对映射.Collection 接口又有 3 ...
- 对Java代码加密的两种方式,防止反编译
使用Virbox Protector对Java项目加密有两种方式,一种是对War包加密,一种是对Jar包加密.Virbox Protector支持这两种文件格式加密,可以加密用于解析class文件的j ...
- Java新建线程的两种方式
Java新建线程有两种方式,一种是通过继承Thread类,一种是实现Runnable接口,下面是新建线程的两种方式. 我们假设有个竞赛,有一个选手A做俯卧撑,一个选手B做仰卧起坐.分别为两个线程: p ...
- 【转载】JAVA中线程的两种实现方法-实现Runnable接口和继承Thread类
转自: http://blog.csdn.net/sunguangran/article/details/6069317 非常感谢原作者,整理的这么详细. 在java中可有两种方式实现多线程,一种是继 ...
- java中线程分两种,守护线程和用户线程。
java中线程分为两种类型:用户线程和守护线程. 通过Thread.setDaemon(false)设置为用户线程: 通过Thread.setDaemon(true)设置为守护线程. 如果不设置次属性 ...
- Java线程创建的两种方式
java多线程总结一:线程的两种创建方式及优劣比较 (一)---之创建线程的两种方式 java实现多线程的两种方法的比较
- iOS 两种不同的图片无限轮播
代码地址如下:http://www.demodashi.com/demo/11608.html 前记 其实想写这个关于无限轮播的记录已经很久很久了,只是没什么时间,这只是一个借口,正如:时间就像海绵, ...
- WebSocket实践——Java实现WebSocket的两种方式
什么是 WebSocket? 随着互联网的发展,传统的HTTP协议已经很难满足Web应用日益复杂的需求了.近年来,随着HTML5的诞生,WebSocket协议被提出,它实现了浏览器与服务器的全双工通信 ...
随机推荐
- Python中的高阶函数与匿名函数
Python中的高阶函数与匿名函数 高阶函数 高阶函数就是把函数当做参数传递的一种函数.其与C#中的委托有点相似,个人认为. def add(x,y,f): return f( x)+ f( y) p ...
- Xamarin.Android之山有木兮之木有枝,心悦君兮君不知。
Xamarin.Android之山有木兮之木有枝,心悦君兮君不知. 第一步,写项目中的第一个界面. <?xml version="1.0" encoding =" ...
- css3动画实例
<!doctype html> <html> <head> <meta charset="utf-8"> <title> ...
- MYbatis调试日记(三)
如何在Mybatis中插入日期类型的数据 直接见代码: xml配置文件 java代码
- NYOJ-205 求余数 AC 分类: NYOJ 2014-02-02 12:30 201人阅读 评论(0) 收藏
这题目看一眼以为难度评级出错了,只是一个求余数的题目,,后来才发现,位数小于百万位,,,我还以为是大小小于百万呢,所以借鉴了另一大神的代码, 用大数,重点是同余定理: (a+b)mod m=((a m ...
- HackPorts – Mac OS X 渗透测试框架与工具
HackPorts是一个OS X 下的一个渗透框架. HackPorts是一个“超级工程”,充分利用现有的代码移植工作,安全专业人员现在可以使用数以百计的渗透工具在Mac系统中,而不需要虚拟机. 工具 ...
- JavaScript事件委托的技术原理
如今的JavaScript技术界里最火热的一项技术应该是‘事件委托(event delegation)’了.使用事件委托技术能让你避免对特定的每个节点添加事件监听器:相反,事件监听器是被添加到它们的父 ...
- 如何在 Swift 语言下使用 iOS Charts API 制作漂亮图表?
[编者按]本文作者 Joyce Echessa 是渥合数位服务创办人,毕业于台湾大学,近年来专注于协助客户进行 App 软体以及网站开发.文中作者通过示例介绍用 ios-charts 库创建简易美观的 ...
- 初步体验javascript try catch机制
javascript在ECMAScript3中引入了try catch finally机制,大致原理和其他语言一样. 我们也可以自定义错误事件. 但是事先声明:我们自定义的错误事件,只支持对name. ...
- Error Code: 1175 Mysql中更新或删除时报错(未带关键字条件)
SET SQL_SAFE_UPDATES = 0; SQL_SAFE_UPDATES = {0 | 1} 如果设置为0,则MySQL会放弃在WHERE子句或LIMIT子句中不使用关键字的UPDATE或 ...