在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. amazeUI modal 模态框 关闭属性

    $('#my-prompt').modal({ relatedTarget: this, closeViaDimmer: false, // 点击外部空白处不关闭弹窗 closeOnConfirm:f ...

  2. WEBservice的浏览器及元素的常用函数及变量整理总结 (selenium )

    由于网页自动化要操作浏览器以及浏览器页面元素,这里笔者就将浏览器及页面元素常用的函数及变量整理总结一下,以供读者在编写网页自动化测试时查阅. from selenium import webdrive ...

  3. ndarray笔记续

    数组的索引与切片 多维数组的索引 import numpy as np arr=np.arange(1,25).reshape(2,3,4) arr # 输出 array([[[ 1, 2, 3, 4 ...

  4. 学界 | 华为诺亚方舟实验室提出新型元学习法 Meta-SGD ,在回归与分类任务中表现超群

    学界 | 华为诺亚方舟实验室提出新型元学习法 Meta-SGD ,在回归与分类任务中表现超群 机器之心发表于机器之心订阅 499 广告关闭 11.11 智慧上云 云服务器企业新用户优先购,享双11同等 ...

  5. IDEA报错: Clone failed: Authentication failed for 'http://10.70.XXXXXXXXXXXXXXXXX'

    今天从git上导入公司的项目,总是报错Clone failed: Authentication failed for 'http://10.70.XXXXXXXXXXXXXX' 在网上百度了一下,大致 ...

  6. Effective Java 读书笔记(三):类与接口

    1 最小化类和成员的可访问性 (1)封装 封装对组成系统的组件进行解耦,从而允许这些组件独立开发,测试,优化,使用,理解和修改. 封装提高了软件的复用性,因为组件间的耦合度低使得它们不仅在开发环境,而 ...

  7. SQL Server 2017 左补齐

    DECLARE @NUM CHAR(3)='7  'SELECT RIGHT('0000000'+CONVERT(VARCHAR(50),1+ RTRIM(@NUM)),7) ​​​​

  8. python实现tcp代理

    1.代理流程图 2.实现代码 #! usr/bin/python2 import sys import socket import thread #handle local buffer def re ...

  9. Keras 笔记

    1. 从 meta 模型恢复graph,   修改node  并保存 from __future__ import absolute_import from __future__ import div ...

  10. RMQ((Range Minimum/Maximum Query))ST算法

    给定一个数组,求出给定区间[l,r]中元素的最大值或最小值或者最值的索引. 一看到这个题目,简单,看我暴力出奇迹.暴力当然是可行的.但是时间复杂度很高(O(n^2)).线段树,树状数组也可以解决这个问 ...