在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. Matlab绘制阶梯形图

    声明:引用请注明出处http://blog.csdn.net/lg1259156776/ 对于Matlab的使用情况常常是这样子的,很多零碎的函数名字很难记忆,经常用过后过一段时间就又忘记了,又得去网 ...

  2. Android_7.1.1_r6源码编译

    上篇文章讲述了如何下载Android源码,在篇文章就来说一说Android源码编译.其实一般来说如果修改的软件和底层没什么关系,直接提取相应的源代码到Android Studio编译就可以了,如果是与 ...

  3. apache-phoenix-5.0.0-HBase-2.0-bin 登陆报错

    1.Error: org.apache.hadoop.hbase.DoNotRetryIOException: java.io.IOException: Unable to load configur ...

  4. php开启多线程下载

    php开启多线程下载 <pre><?php/** * 多进程批量下载文件(使用php curl_multi_exec实现) * Date: 2017-07-16 * Author: ...

  5. RocketMQ之三:RocketMQ集群环境搭建

    1.初步理解Producer/Consumer Group 在安装RocketMQ之前我们先来理解Group概念,在RocketMQ中Group是很重要的.通过Group机制,让RocketMQ天然的 ...

  6. 注册中心Eureka 说明

    Eureka是Netflix开发的服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中间层服务故障转移的目的.SpringCloud将它集成在其子项 ...

  7. Python标准库之sched模块介绍

    sched——通用时间调度器 sched模块实现了一个通用事件调度器,在调度器类使用一个延迟函数等待特定的时间,执行任务.同时支持多线程应用程序,在每个任务执行后会立刻调用延时函数,以确保其他线程也能 ...

  8. 十、LCD的framebuffer设备驱动

    在读者学习本章以及后续LCD相关章节之前,最好拥有LCD裸机基础,可以参考:LCD编程. 在内核中,表示LCD使用的是framebuffer(帧缓冲,简写为fb),其内容对应于屏幕上的界面显示.修改f ...

  9. SysTick 定时实验(中断)

    实验目的:利用 SysTick 产生 1s 的时基,LED 以 1s 的频率闪烁. 编程要点 1.设置重装载寄存器的值 2.清除当前数值寄存器的值 3.配置控制与状态寄存器 过程 我们创建了两个文件: ...

  10. MongoDB添加删除节点

    副本集添加删除节点 sharding添加删除节点 先将节点设置为hidden,再remove