java应用本地缓存

时间:2022-11-12 11:08:15

 
      在java应用中,对于访问频率比较高,又不怎么变化的数据,常用的解决方案是把这些数据加入缓存。相比DB,缓存的读取效率快好不少。java应用缓存一般分两种,一是进程内缓存,就是使用java应用虚拟机内存的缓存;另一个是进程外缓存,现在我们常用的各种分布式缓存。相比较而言,进程内缓存比进程外缓存快很多,而且编码也简单;但是,进程内缓存的存储量有限,使用的是java应用虚拟机的内存,而且每个应用都要存储一份,有一定的资源浪费。进程外缓存相比进程内缓存,会慢些,但是,存储空间可以横向扩展,不受限制。
 
     这里是几中场景的访问时间
 
-------------------------------------------------------------------
|         从数据库中读取一条数据(有索引)        |  十几毫秒  |
|         从远程分布式缓存读取一条数据              |  0.5毫秒    |
|         从内存中读取1MB数据                         |  十几微妙  |
-------------------------------------------------------------------
 
      进程内缓存和进程外缓存,各有优缺点,针对不同场景,可以分别采用不同的缓存方案。对于数据量不大的,我们可以采用进程内缓存。或者只要内存足够富裕,都可以采用,但是不要盲目以为自己富裕,不然可能会导致系统内存不够。
 
     下面要分享的是一个代码级别的,对进程内缓存的经验总结。面向jdk1.8版本。
 
    在有效时间内缓存单个对象
public class LiveCache<T> {
// 缓存时间
private final int cacheMillis;
// 缓存对象
private final T element;
// 缓存对象创建时间
private final long createTime; public LiveCache(int cacheMillis, T element) {
this.cacheMillis = cacheMillis;
this.element = element;
this.createTime = System.currentTimeMillis();
} // 获取缓存对象
public T getElement() {
long currentTime = System.currentTimeMillis();
if(cacheMillis > 0 && currentTime - createTime > cacheMillis) {
return null;
} else {
return element;
}
} // 获取缓存对象,忽略缓存时间有效性
public T getElementIfNecessary() {
return element;
}
} public static void main(String[] args) {
int cacheMilis = 1000 ;
LiveCache<Object> liveCache = new LiveCache<>(cacheMilis, new Object()) ; liveCache.getElement() ;
liveCache.getElementIfNecessary() ; }
    有效时间内,缓存单个对象,可异步刷新
@FunctionalInterface
public interface LiveFetch<T> {
// 刷新缓存接口
T fetch() ;
} public class LiveManager<T> {
// 缓存时间
private int cacheMillis;
// 缓存对象
private LiveCache<T> liveCache;
// 刷新缓存的对象
private LiveFetch<T> liveFetch ; private Logger logger = LoggerFactory.getLogger(LiveManager.class) ; // 刷新缓存开关
private boolean refresh = false ; public LiveManager(int cacheMillis, LiveFetch<T> liveFetch) {
this.cacheMillis = cacheMillis ;
this.liveFetch = liveFetch ;
} /**
* fetch cache ; if cache expired , synchronous fetch
* @return
*/
public T getCache() { initLiveCache(); if(liveCache != null) {
T t ;
if((t= liveCache.getElement()) != null) {
return t ;
} else {
t = liveFetch.fetch() ;
if(t != null) {
liveCache = new LiveCache<T>(cacheMillis, t) ;
return t ;
}
}
} return null ;
} /**
* fetch cache ; if cache expired , return old cache and asynchronous fetch
* @return
*/
public T getCacheIfNecessary() { initLiveCache(); if(liveCache != null) {
T t ;
if((t= liveCache.getElement()) != null) {
return t ;
} else {
refreshCache() ;
return liveCache.getElementIfNecessary() ;
}
} return null ;
} /**
* init liveCache
*/
private void initLiveCache() {
if(liveCache == null) {
T t = liveFetch.fetch() ;
if(t != null) {
liveCache = new LiveCache<T>(cacheMillis, t) ;
}
}
} /**
* asynchronous refresh cache
*/
private void refreshCache() { if(refresh)
return ;
refresh = true ;
try {
Thread thread = new Thread(() -> {
try {
T t = liveFetch.fetch();
if (t != null) {
liveCache = new LiveCache<>(cacheMillis, t);
}
} catch (Exception e){
logger.error("LiveManager.refreshCache thread error.", e);
} finally {
refresh = false ;
}
}) ;
thread.start();
} catch (Exception e) {
logger.error("LiveManager.refreshCache error.", e);
}
}
} public class Test { public static void main(String[] args) {
int cacheMilis = 1000 ;
LiveManager<Object> liveManager = new LiveManager<>(cacheMilis,() -> new Test().t1()) ; liveManager.getCache() ;
liveManager.getCacheIfNecessary() ;
} public Object t1(){ return new Object() ;
}
}
    有效缓存内,缓存多个对象,map结构存储,可异步刷新
@FunctionalInterface
public interface LiveMapFetch<T> {
// 异步刷新数据
T fetch(String key) ;
} public class LiveMapManager<T> { private int cacheMillis;
private Map<String,LiveCache<T>> liveCacheMap;
private LiveMapFetch<T> liveMapFetch; private Logger logger = LoggerFactory.getLogger(LiveMapManager.class) ; private boolean refresh = false ; public LiveMapManager(int cacheMillis, LiveMapFetch<T> liveMapFetch) {
this.cacheMillis = cacheMillis ;
this.liveMapFetch = liveMapFetch ;
} /**
* fetch cache ; if cache expired , synchronous fetch
* @return
*/
public T getCache(String key) { initLiveCache(); T t ;
if(liveCacheMap.containsKey(key) && (t = liveCacheMap.get(key).getElement()) != null) {
return t ;
} else {
t = liveMapFetch.fetch(key) ;
if(t != null) {
LiveCache<T> liveAccess = new LiveCache<T>(cacheMillis, t) ;
liveCacheMap.put(key, liveAccess) ;
return t ;
}
} return null ;
} /**
* fetch cache ; if cache expired , return old cache and asynchronous fetch
* @return
*/
public T getCacheIfNecessary(String key) { initLiveCache(); T t ;
if(liveCacheMap.containsKey(key) && (t = liveCacheMap.get(key).getElement()) != null) {
return t ;
} else {
if(liveCacheMap.containsKey(key)) {
refreshCache(key) ;
return liveCacheMap.get(key).getElementIfNecessary() ;
} else {
t = liveMapFetch.fetch(key) ;
if(t != null) {
LiveCache<T> liveAccess = new LiveCache<T>(cacheMillis, t) ;
liveCacheMap.put(key, liveAccess) ;
return t ;
}
}
}
return t ;
} /**
* init liveCache
*/
private void initLiveCache() {
if(liveCacheMap == null) {
liveCacheMap = new HashMap<>() ;
}
} /**
* asynchronous refresh cache
*/
private void refreshCache(String key) { if(refresh)
return ;
refresh = true ;
try {
Thread thread = new Thread(() -> {
try {
T t = liveMapFetch.fetch(key);
if (t != null) {
LiveCache<T> liveAccess = new LiveCache<>(cacheMillis, t);
liveCacheMap.put(key, liveAccess);
}
} catch (Exception e) {
logger.error("LiveMapManager.refreshCache thread error.key:",e);
} finally {
refresh = false ;
}
}) ;
thread.start();
} catch (Exception e) {
logger.error("LiveMapManager.refreshCache error.key:" + key, e);
}
} } public class Test { public static void main(String[] args) {
int cacheMilis = 1000 ;
LiveMapManager<Object> liveManager = new LiveMapManager<>(cacheMilis,(String key) -> new Test().t1(key)) ; liveManager.getCache("key") ;
liveManager.getCacheIfNecessary("key") ;
} public Object t1(String key){ return new Object() ;
}
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

java应用本地缓存的更多相关文章

  1. Java学习之ConcurrentHashMap实现一个本地缓存

    ConcurrentHashMap融合了Hashtable和HashMap二者的优势. Hashtable是做了线程同步,HashMap未考虑同步.所以HashMap在单线程下效率较高,Hashtab ...

  2. Java本地缓存解决方案其一(使用Google的CacheBuilder)

    前不久,业务实现上需要用到本地缓存来解决一些数据量相对较小但是频繁访问的数据,通过查找各种资料,找到了一种可以实现的方案--采用的是Google的CacheBuilder.下面是代码实现过程:1.首先 ...

  3. Caffeine Cache-高性能Java本地缓存组件

    前面刚说到Guava Cache,他的优点是封装了get,put操作:提供线程安全的缓存操作:提供过期策略:提供回收策略:缓存监控.当缓存的数据超过最大值时,使用LRU算法替换.这一篇我们将要谈到一个 ...

  4. 实现 Java 本地缓存,该从这几点开始

    缓存,我相信大家对它一定不陌生,在项目中,缓存肯定是必不可少的.市面上有非常多的缓存工具,比如 Redis.Guava Cache 或者 EHcache.对于这些工具,我想大家肯定都非常熟悉,所以今天 ...

  5. java中的本地缓存

    java中的本地缓存,工作后陆续用到,一直想写,一直无从下手,最近又涉及到这方面的问题了,梳理了一下.自己构造单例.guava.ehcache基本上涵盖了目前的大多数行为了.   为什么要有本地缓存? ...

  6. 第七章 企业项目开发--本地缓存guava cache

    1.在实际项目开发中,会使用到很多缓存技术,而且数据库的设计一般也会依赖于有缓存的情况下设计. 常用的缓存分两种:本地缓存和分布式缓存. 常用的本地缓存是guava cache,本章主要介绍guava ...

  7. A comparison of local caches &lpar;1&rpar; 【本地缓存之比较 &lpar;1&rpar;】

    1. Spring local cache   [Spring 本地缓存] Spring provided cacheable annotation since 3.1. It's very supe ...

  8. A comparison of local caches &lpar;2&rpar; 【本地缓存之比较 &lpar;2&rpar;】

    接上一篇: A comparison of local caches (1) [本地缓存之比较 (1)] This article will compare the asynchronous loca ...

  9. redis订阅发布消息操作本地缓存

    Redis 本地缓存+远程缓存方案 使用纯java的ehcache作为本地缓存 Reids 作为远程分布式缓存 解决redis缓存压力过大,提高缓存速度,以及缓存性能. Redis和ehcache缓存 ...

随机推荐

  1. ACM&sol;ICPC 之 两道dijkstra练习题&lpar;ZOJ1053&lpar;POJ1122&rpar;-ZOJ1053&rpar;

    两道较为典型的单源最短路径问题,采用dijkstra解法 本来是四道练习题,后来发现后面两道用dijkstra来解的话总觉得有点冗余了,因此暂且分成三篇博客(本篇以及后两篇). ZOJ1053(POJ ...

  2. AngularJS快速入门指南06:过滤器

    thead>tr>th, table.reference>tbody>tr>th, table.reference>tfoot>tr>th, table ...

  3. license文件生成原理

      byte解密weblogic加密oraclehex 现在很多J2EE应用都采用一个license文件来授权系统的使用,特别是在系统购买的早期,会提供有限制的license文件对系统进行限制,比如试 ...

  4. java&period;nio分析软件包&lpar;三&rpar;---Charset理解力

    前面的分析后,2一个基本的封装类型.现在我们就来揭开Java.nio魔法知识的最后一块,CharsetEncoding类,他的主要功能是实现字节Unicode之间的转换转码. 让我们来看看他同样的封装 ...

  5. 中秋H5,这篇脑洞开的可以!

    案例:嫦娥--寻开心出品:凯迪仕 1.内容:这是一支视频类H5案例.Loading完毕进入页面,首屏提示案例最佳观看方式为先锁屏再横屏.点击开始按钮播放视频,视频讲述"葫芦娃"缠着 ...

  6. 面试题之小炼牛刀zip&comma;lambda&comma;map

    # 现有两元祖,(('a'),('b')),(('c'),('d'))# 请使用python中匿名函数生成列表[{'a':'c'},{'b':'d'}]t1=(('a'),('b'))t2=(('c' ...

  7. SuperMap 三维产品资料一览表

    转自:http://blog.csdn.net/supermapsupport/article/details/68924713 如何能快速地开发项目中的三维功能呢?本文为您提供全方位的三维资料,为您 ...

  8. Keepalived基础知识-运维小结

    keepalived介绍keepalived观察其名可知,保持存活,在网络里面就是保持在线了,也就是所谓的高可用或热备,它集群管理中保证集群高可用的一个服务软件,其功能类似于heartbeat,用来防 ...

  9. Git &amp&semi; GitHub 的安装配置

    参考   教你免费搭建个人博客,Hexo&Github   安装Git 1. 注册 GitHub 注册.登录 https://github.com/ 2. 创建仓库 在 GitHub 的右上角 ...

  10. English trip -- VC&lpar;情景课&rpar; 7 A Shopping 购物

    Words The clothes place a dress 长裙      short skirt 短裙 pants 裤子   /  trousers 长裤  / shorts 短裤 a shir ...