通过ConcurrentHashMap实现本地缓存
2017-03-19 10:04
113 查看
在做项目的时候,往往遇到需要使用缓存,但是缓存的量不大,没有必要使用redis这样的缓存。比如我做一个定时任务,捞取从什么时间之后需要发货的订单,想要把这个时间点做一个配置,所以自己使用ConcurrentHashMap实现了一个简单的缓存
package cahche;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class StaticCache {
private static Map<String, Element> map = new ConcurrentHashMap<>();
/**
* @Desc
* @Date 2017年3月19日上午10:19:40
* @param key 缓存key
* @param value 缓存value
* @param expireTime 缓存过期时间(秒)
*/
public static void set(String key, String value, int expireTime){
Date expireDate = CalculateSecondTimeInterval(new Date(), expireTime) ;
map.put(key, new Element(value, expireDate));
}
/**
* @Desc
* @Date 2017年3月19日上午10:20:26
* @param key 缓存key
* @return
*/
public static String get(String key){
if(map.containsKey(key) && map.get(key).getExpireDate().after(new Date())){
return map.get(key).getValue();
}
return null;
}
private static Date CalculateSecondTimeInterval(Date baseDate,int timeDiff){
Calendar calendar = Calendar.getInstance();
calendar.setTime(baseDate);
calendar.add(Calendar.SECOND, timeDiff);
return calendar.getTime();
}
}
class Element{
private String value;
private Date expireDate;
public Element(String value, Date expireDate) {
super();
this.value = value;
this.expireDate = expireDate;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public Date getExpireDate() {
return expireDate;
}
public void setExpireDate(Date expireDate) {
this.expireDate = expireDate;
}
}
测试代码:
package cahche;
public class TestCache{
private final static String QUERY_DELIVERY_DAY_KEY = "query.delivery.days";
public static void main(String[] args) throws InterruptedException {
if(StaticCache.get(QUERY_DELIVERY_DAY_KEY) == null){
//直接查询配置
String day = "30";
//更新缓存,设置缓存失效时间为60s
StaticCache.set(QUERY_DELIVERY_DAY_KEY, day, 3);
System.out.println("缓存设置成功");
}
System.out.println("获取query.delivery.days的值:" + StaticCache.get(QUERY_DELIVERY_DAY_KEY));
//等待3s
Thread.sleep(3*1000);
System.out.println("3s后获取query.delivery.days的值:" + StaticCache.get(QUERY_DELIVERY_DAY_KEY));
}
}
结果:
缓存设置成功
获取query.delivery.days的值:30
3s后获取query.delivery.days的值:null
需要注意几点:
1、在多线程环境下不能使用HashMap,原因是在多线程put的时候可能出现元素丢失的情况,更严重的是在HashMap reHash时可能会出现死循环的链表,导致get操作一直循环下去,造成CPU被打满的情况
2、由于static所指向的全局变量在GC的时候作为GC Root不会被回收掉,从而整个map中的元素都不能被GC掉,当整个map的元素过多的时候,会导致堆内存溢出。这种方案只适合用于小数量的缓存
参考:https://my.oschina.net/xianggao/blog/393990
package cahche;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class StaticCache {
private static Map<String, Element> map = new ConcurrentHashMap<>();
/**
* @Desc
* @Date 2017年3月19日上午10:19:40
* @param key 缓存key
* @param value 缓存value
* @param expireTime 缓存过期时间(秒)
*/
public static void set(String key, String value, int expireTime){
Date expireDate = CalculateSecondTimeInterval(new Date(), expireTime) ;
map.put(key, new Element(value, expireDate));
}
/**
* @Desc
* @Date 2017年3月19日上午10:20:26
* @param key 缓存key
* @return
*/
public static String get(String key){
if(map.containsKey(key) && map.get(key).getExpireDate().after(new Date())){
return map.get(key).getValue();
}
return null;
}
private static Date CalculateSecondTimeInterval(Date baseDate,int timeDiff){
Calendar calendar = Calendar.getInstance();
calendar.setTime(baseDate);
calendar.add(Calendar.SECOND, timeDiff);
return calendar.getTime();
}
}
class Element{
private String value;
private Date expireDate;
public Element(String value, Date expireDate) {
super();
this.value = value;
this.expireDate = expireDate;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public Date getExpireDate() {
return expireDate;
}
public void setExpireDate(Date expireDate) {
this.expireDate = expireDate;
}
}
测试代码:
package cahche;
public class TestCache{
private final static String QUERY_DELIVERY_DAY_KEY = "query.delivery.days";
public static void main(String[] args) throws InterruptedException {
if(StaticCache.get(QUERY_DELIVERY_DAY_KEY) == null){
//直接查询配置
String day = "30";
//更新缓存,设置缓存失效时间为60s
StaticCache.set(QUERY_DELIVERY_DAY_KEY, day, 3);
System.out.println("缓存设置成功");
}
System.out.println("获取query.delivery.days的值:" + StaticCache.get(QUERY_DELIVERY_DAY_KEY));
//等待3s
Thread.sleep(3*1000);
System.out.println("3s后获取query.delivery.days的值:" + StaticCache.get(QUERY_DELIVERY_DAY_KEY));
}
}
结果:
缓存设置成功
获取query.delivery.days的值:30
3s后获取query.delivery.days的值:null
需要注意几点:
1、在多线程环境下不能使用HashMap,原因是在多线程put的时候可能出现元素丢失的情况,更严重的是在HashMap reHash时可能会出现死循环的链表,导致get操作一直循环下去,造成CPU被打满的情况
2、由于static所指向的全局变量在GC的时候作为GC Root不会被回收掉,从而整个map中的元素都不能被GC掉,当整个map的元素过多的时候,会导致堆内存溢出。这种方案只适合用于小数量的缓存
参考:https://my.oschina.net/xianggao/blog/393990
相关文章推荐
- 微信小程序通过本地缓存实现点赞功能
- Web开发中的缓存技术之三:通过ETag实现缓存处理(ASP.NET MVC版)
- 通过Windows Azure Connect ,实现本地机器与Windows Azure 虚拟机的相互连接(转+译)
- Android 通过软引用实现图片缓存,防止内存溢出
- Android 通过软引用实现图片缓存,防止内存溢出
- 如何实现自动把域帐户加到本地管理员组里?如果通过脚本实现
- 使用ASIHTTPRequest和ASIDownloadCache实现本地缓存
- 通过软引用实现图片缓存,防止内存溢出
- 通过注册新协议实现网页链接打开本地程序
- Android 通过软引用实现图片缓存,防止内存溢出
- 通过Windows Azure Connect ,实现本地机器与Windows Azure 虚拟机的相互连接(转+译)
- Javascript缓存环,通过类切换方式来实现
- 通过ssh实现在本地WIN7系统下访问虚拟机中的Linux系统
- 通过Windows Azure Connect ,实现本地机器与Windows Azure 虚拟机的相互连接(转+译)
- 用JavaScript实现本地缓存
- 通过Windows Azure Connect ,实现本地机器与Windows Azure 虚拟机的相互连接(转+译)
- 用JavaScript实现本地缓存
- Android本地缓存和远程图片获取的实现
- iPhone开发笔记(16)使用ASIHTTPRequest和ASIDownloadCache实现本地缓存