在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高性能本地缓存框架Caffeine

    一.序言 Caffeine是一个进程内部缓存框架,使用了Java 8最新的[StampedLock]乐观锁技术,极大提高缓存并发吞吐量,一个高性能的 Java 缓存库,被称为最快缓存. 二.缓存简介 ...

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

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

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

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

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

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

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

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

  6. java中的本地缓存

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

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

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

  8. A comparison of local caches (1) 【本地缓存之比较 (1)】

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

  9. A comparison of local caches (2) 【本地缓存之比较 (2)】

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

随机推荐

  1. 综合练习1,划分vlan,单臂路由,DHCP服务及其限制网段、租期,设置根桥,OSPF路由通告综合练习

    实验要求: 1.在LSW1上分别给vlan10和vlan20做DHCP网段分别为192.168.10.0/24.192.168.20.0/24禁用192.168.10.200-253,192.168. ...

  2. 第一周--------Java的特性和优势

    --------我认可的1.跨平台性:   Java 的int 永远是32位,不像C++可能是16.,32 可能是根据编译器厂商规定的变化.这样的话,程序的移植就会变得困难2.安全性    Java ...

  3. [转帖]Docker中的时区问题处理

    Docker中的时区问题处理 这两天在打docker的时候,发现自己的容器启动之后,里面date -R的输出时区是UTC,总是和北京时间差了8个小时. 作者:云平台运维开发来源:今日头条|2019-0 ...

  4. [tensorflow] 入门day1-数据整理与展示

    tensorflow真是一个我绕不开的坑(苍天饶过谁.jpg) 其实tensorflow1和2的差别挺大的,暂时从1入坑,2的话之后简单过一下. tf2中更改的函数(供参考):https://docs ...

  5. VMware安装windows7系统

    1.进入VMware系统,选择创建新的虚拟机 2.进入安装页面,选择自定义安装 3.选择虚拟机硬件兼容性,选择与自己软件相匹配的硬件兼容性 4.选择下一步后,选择稍后安装操作系统 5.选择客户机操作系 ...

  6. go 结构的方法总结

    方法可以与命名类型或命名类型的指针关联. 刚刚看到的两个 Abs 方法.一个是在 *Vertex 指针类型上,而另一个在 MyFloat 值类型上. 有两个原因需要使用指针接收者.首先避免在每个方法调 ...

  7. go 函数定义

    -------------------------------------------- package main import "fmt" func add(x int, y i ...

  8. Python开发【第七章】:异常处理

    一.异常处理 1.异常基础 在编程过程中为了增加友好性,在程序出现bug时一般不会将错误信息显示给用户,而是现实一个提示的页面,通俗来说就是不让用户看见大黄页!!! #异常处理 list = [&qu ...

  9. axios 发送post请求

    目录 方案一 方案二 方案一 在node中使用axios以post的方式发送一张图片给某个server时: let data = fs.createReadStream(__dirname + '/t ...

  10. SVN操作出现locked错误解决办法

    SVN操作出现locked错误解决办法:在SVN中执行 commit 操作时,在更新过程中,中断过,或者因为其他原因导致SVN 出现 locked 异常. 解决办法:1. 选中出现异常的文件,右键 - ...