今天和同事聊到了缓存,在Java中实现进程缓存。这里主要思想是,用一个map做缓存。缓存有个生存时间,过期就删除缓存。这里可以考虑两种删除策略,一种是起一个线程,定期删除过期的key。第二个是,剔除模式,比较懒,访问到某个key的时候才,才去检查这个key是否过期,过期删除。

首先,对要缓存的value做了层封装,带了个时间戳

/**
* Created by gxf on 2017/6/28.
*/
public class ValueWithTimeStamp<V>{
private long expireTime;
private V value; public ValueWithTimeStamp(long expireTime, V value) {
this.expireTime = expireTime;
this.value = value;
} public long getExpireTime() {
return expireTime;
} public void setExpireTime(long expireTime) {
this.expireTime = expireTime;
} public V getValue() {
return value;
} public void setValue(V value) {
this.value = value;
}
}

ok,起线程定期删除策略的模式

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; /**
* Created by gxf on 2017/6/28.
* 使用线程,定期删除过期的key
*/
public class CacheMap<K, V> {
//这里使用ConcurrentHashMap避免,clean的时候,主线程修改chache,造成异常,
//使用ConcurrentHashMap可以控制并发修改cache
private Map<K, ValueWithTimeStamp<V>> cache = new ConcurrentHashMap<K, ValueWithTimeStamp<V>>();
private static boolean cleanTaskIsRunning = false; //ttl 过期时间 单位:秒
public void put(K key, V value, int ttl){
long expireTime = System.currentTimeMillis() + ttl * 1000;
ValueWithTimeStamp<V> valueWithTimeStamp = new ValueWithTimeStamp<>(expireTime, value);
cache.put(key, valueWithTimeStamp);
if(!cleanTaskIsRunning){
startCleanTask();
cleanTaskIsRunning = !cleanTaskIsRunning;
}
} public V get(K key){
ValueWithTimeStamp<V> valueWithTimeStamp = cache.get(key);
return null == valueWithTimeStamp ? null : valueWithTimeStamp.getValue();
} /**
* 启动清理线程
* */
private void startCleanTask(){
Thread cleanThread = new Thread(new CleanTask());
cleanThread.start();
} /**
* 清理过期的key
* */
class CleanTask implements Runnable{
public void run(){
while(true){
long currentTime = System.currentTimeMillis();
//遍历map
for(Map.Entry<K, ValueWithTimeStamp<V>> entry : cache.entrySet()){
ValueWithTimeStamp<V> valueWithTimeStamp = entry.getValue();
long expireTime = valueWithTimeStamp.getExpireTime();
//过期时间到了
if(currentTime > expireTime){
System.out.println("key : " + entry.getKey() + " expired ");
cache.remove(entry.getKey());
} //if
} //for
//每隔1s扫描map对象
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} //while
}
}
}

注意,这里需要使用ConcurrentHashMap做缓存。不然会出现多线线程操作map对象的异常

第二种策略,剔除模式

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; /**
* Created by 58 on 2017/6/28.
* 这里使用懒惰模式,获取key的时候,才剔除过期的key
*/
public class CacheMap1<K, V> {
private Map<K, ValueWithTimeStamp<V>> cache = new ConcurrentHashMap<K, ValueWithTimeStamp<V>>(); public void put(K key, V value, int ttl){
long expireTime = System.currentTimeMillis() + ttl * 1000;
ValueWithTimeStamp<V> valueWithTimeStamp = new ValueWithTimeStamp<V>(expireTime, value);
cache.put(key, valueWithTimeStamp);
} public V get(K key){
ValueWithTimeStamp<V> valueWithTimeStamp = cache.get(key);
long expireTime = valueWithTimeStamp.getExpireTime();
long currentTime = System.currentTimeMillis();
//key已经过期,删除,返回null
if(currentTime > expireTime){
System.out.println("key :" + key + " is expired.");
cache.remove(key);
return null;
} return cache.get(key).getValue();
}
}

项目中用到了redis,用这种方式应该会更快,这两天优化一下代码

Java进程内缓存的更多相关文章

  1. Java的进程内缓存框架:EhCache (转)

    EhCache 是一个纯Java的进程内缓存框架,具有快速.精干等特点,是Hibernate中默认的CacheProvider. Ehcache缓存的特点: 1. 快速. 2. 简单. 3. 多种缓存 ...

  2. Java的进程内缓存框架:EhCache

    EhCache 是一个纯Java的进程内缓存框架,具有快速.精干等特点,是Hibernate中默认的CacheProvider.   Ehcache缓存的特点: 1. 快速. 2. 简单. 3. 多种 ...

  3. 一文深入了解史上最强的Java堆内缓存框架Caffeine

    它提供了一个近乎最佳的命中率.从性能上秒杀其他一堆进程内缓存框架,Spring5更是为了它放弃了使用多年的GuavaCache 缓存,在我们的日常开发中用的非常多,是我们应对各种性能问题支持高并发的一 ...

  4. spring boot:使用spring cache+caffeine做进程内缓存(本地缓存)(spring boot 2.3.1)

    一,为什么要使用caffeine做本地缓存? 1,spring boot默认集成的进程内缓存在1.x时代是guava cache 在2.x时代更新成了caffeine, 功能上差别不大,但后者在性能上 ...

  5. Spring Boot 2.x基础教程:进程内缓存的使用与Cache注解详解

    随着时间的积累,应用的使用用户不断增加,数据规模也越来越大,往往数据库查询操作会成为影响用户使用体验的瓶颈,此时使用缓存往往是解决这一问题非常好的手段之一.Spring 3开始提供了强大的基于注解的缓 ...

  6. java 整合redis缓存 SSM 后台框架 rest接口 shiro druid maven bootstrap html5

    A 调用摄像头拍照,自定义裁剪编辑头像,头像图片色度调节B 集成代码生成器 [正反双向](单表.主表.明细表.树形表,快速开发利器)+快速表单构建器 freemaker模版技术 ,0个代码不用写,生成 ...

  7. java应用本地缓存

            在java应用中,对于访问频率比较高,又不怎么变化的数据,常用的解决方案是把这些数据加入缓存.相比DB,缓存的读取效率快好不少.java应用缓存一般分两种,一是进程内缓存,就是使用ja ...

  8. java问题排查工具之一板斧jstack——使用 jstack 定位 java进程CPU过高的问题

    jstack主要用来查看某个Java进程内的线程堆栈信息.语法格式如下: jstack [option] pid jstack [option] executable core jstack [opt ...

  9. JVM探秘:VisualVM监控远程Java进程

    VisualVM在Java 8中是JDK自带的一个图形化工具,项目主页 VisualVM,在后续版本中可能会从JDK移除. VisualVM可以监控Java进程的CPU与内存占用情况,可以监控Java ...

随机推荐

  1. Ubuntu 安装后的配置及美化(一)

    Ubuntu 安装后的配置及美化(一) 记录一下 完成后的主界面. 配置 1.更新源为阿里云 找到 软件和更新 选项,更新源为阿里云的源. 在 其他软件 中将 Canonical合作伙伴 打上勾. 然 ...

  2. 更改Linux下的时间

    1.使用tzseletect glibc-common-2.12-1.192.el6.x86_64 : Common binaries and locale data for glibc Repo : ...

  3. SpringBoot中 application.yml /application.properties常用配置介绍

    # Tomcat server: tomcat: uri-encoding: UTF-8 max-threads: 1000 min-spare-threads: 30 port: 10444 ser ...

  4. SOAP XML报文解析

    import java.util.HashMap;import java.util.List;import java.util.Map; import org.dom4j.Document;impor ...

  5. day--40 mysql-视图,触发器,存储过程,函数总结

    视图,触发器,存储过程,函数总结 一:视图 01:介绍 视图是一个虚拟表(非真实存在),是跑到内存中的表,真实表是硬盘上的表,怎么就得到了虚拟表,就是你查询的结果,只不过之 前我们查询出来的虚拟表,从 ...

  6. 记一个SpringBoot中属性注入失败的问题Consider defining a bean of type ''' in your configuration

    今天遇到的一个问题: 代码检查了好几次,都没有错误,但是启动时就会报错Consider defining a bean of type ''' in your configuration. 启动类在c ...

  7. python学习,day2:列表的复制

    主要涉及列表的潜复制(第二层受后面修改的影响)和深复制(不受后面修改的影响) 代码如下 # coding=utf-8 # Author: RyAn Bi import copy names = ['A ...

  8. pyc和pycodeobject

    Python是一个先编译再解释的语言. 执行过程:先寻找pyc文件,找到则载入,没找到则把编译的结果保存在pycodeobject中,运行结束则写到pyc文件中

  9. redis 连接字符串,设置密码

    <add name="Abp.Redis.Cache" connectionString="127.0.0.1:6379,password=123456" ...

  10. codeforces 1072D Minimum path bfs+剪枝 好题

    题目传送门 题目大意: 给出一幅n*n的字符,从1,1位置走到n,n,会得到一个字符串,你有k次机会改变某一个字符(变成a),求字典序最小的路径. 题解: (先吐槽一句,cf 标签是dfs题????) ...