java ehcache lru_ehcache缓存淘汰浅析
最近要设计个缓存系统,所以到处看了看,简单看了ehcache,不得不感叹源码太多了,能写成这样也I服了Y,还是像google的guava看齐吧,当然ehcache号称支持分布式
1简单使用
记录下简单使用,主要是看源码的时候可以找到入口
http://passover.blog.51cto.com/2431658/486709
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
/>
maxElementsInMemory="5" //缓存中允许创建的最大对象数
maxElementsOnDisk = "5"
eternal="false"//缓存中对象是否为永久的,如果是,超时设置将被忽略,对象从不过期。
timeToIdleSeconds="1440" //缓存数据的钝化时间,也就是在一个元素消亡之前,两次访问时间的最大时间间隔值
diskPersistent="false"
timeToLiveSeconds="2880" //缓存数据的生存时间,也就是一个元素从构建到消亡的最大时间间隔值
overflowToDisk="false"//内存不足时,是否启用磁盘缓存
memoryStoreEvictionPolicy="FIFO"//缓存满了之后的淘汰算法
statistics="true"
/>
public class EhcacheTest {
private static final Logger logger = Logger.getLogger(EhcacheTest.class);
private static Cache sampleCache = null;
public static void main(String[]args) {
init();
test();
}
private static void test() {
logger.info(sampleCache.getMemoryStoreEvictionPolicy());
for(inti=0; i<10; i++){
//写入缓存
sampleCache.put(new Element(i, "v" + i));
//打印当前缓存的所有值
logger.info(sampleCache.getKeys());
//读取缓存
Element e = sampleCache.get(i);
logger.info(e.getValue());
}
//打印命中统计
logger.info(sampleCache.getStatistics());
}
private static voidinit() {
CacheManager manager = CacheManager.create();
// manager.addCache("sample"); //已经在配置文件定义过了
sampleCache = manager.getCache("sample");
}
}
另一种使用方式:
String name = "Namespace";
intcapacity = 500;
intrefreshPeriod = 5000;
// Initialize EhCache
Cache cache = new Cache(name, capacity, false, false, refreshPeriod, 0);
cache.initialise();
System.out.println(
"Initialize EhCache: " +
" name: " + name +
" capacity: " + capacity +
" expire: " + refreshPeriod
);
// Set data into EhCache
String key1 = "Key";
String value1 = "Value";
Element element1 = new Element(key1, value1);
cache.put(element1);
System.out.println("Set (" + key1 + ", " + value1 + ") into EhCache.");
// Get data from EhCache
Element element2 = cache.get(key1);
String key2 = (String) element2.getObjectKey();
String value2 = (String) element2.getObjectValue();
System.out.println("Get (" + key2 + ", " + value2 + ") from EhCache.");
// Remove data from EhCache
if (cache.remove(key2)) {
System.out.println("Remove data with key = " + key2 + " successfully.");
}
// Get EhCache size
System.out.println("EhCache size is " + cache.getSize());
最重要的入口就是CacheManager和Cache,Manager起到类似工厂的作用,主要还是看Cache
2CacheManager
CacheManager,默认会去找ehcache.xml以及ehcache-failsafe.xml等文件,最后创建的是一个Cache对象
private void addConfiguredCaches(ConfigurationHelper configurationHelper) {
// 根据配置创建缓存Cache对象
Set unitialisedCaches = configurationHelper.createCaches();
for (Iterator iterator = unitialisedCaches.iterator();
iterator.hasNext();) {
EhcacheunitialisedCache = (Ehcache) iterator.next();
//调用Cache的init方法
addCacheNoCheck(unitialisedCache, true);
......
}
}
}
============================================================
//在Cache的init方法中,会根据不同的淘汰策略,选择不同的Store
if (useClassicLru &&
configuration.getMemoryStoreEvictionPolicy().equals(
MemoryStoreEvictionPolicy.LRU)) {
//老的LRU策略,选择LruMemoryStore
Store disk = createDiskStore();
store = new LegacyStoreWrapper(new LruMemoryStore(this, disk), disk,registeredEventListeners, configuration);
} else {
//可以存到磁盘,DiskBackedMemoryStore(Memory和DiskStore的整合)
//新的淘汰机制,貌似会有些问题
if (configuration.isOverflowToDisk()) {
store = DiskBackedMemoryStore.create(this, onHeapPool, onDiskPool);
} else {
//只在内存上,MemoryOnlyStore
store = MemoryOnlyStore.create(this, onHeapPool);
}
}
store可以有很多实现,包括DiskBackedMemory(使用DiskStore)或者MemoryOnlyStore(使用MemoryStore)或者
LocalTransactionStore/JtaLocalTransactionStore之类的,分布式的靠Listener去实现,cache的put、update、remove、evict等操作都会发出事件,然后由listener去实现,比如RMISynchronousCacheReplicator
这些store的实现都和ConcurrentHashMap类似,也是分段,默认分64个段即64个锁
3淘汰机制
LFU最不经常使用,计算频率,也就是get的次数
FIFO先进先出,计算下写入时间
LRU最近最少使用,有些使用链表,有些只是记录一个最后访问时间
是否要淘汰都是根据最大容量,超过最大容量后,就会根据指定的策略淘汰数据,先看看新的淘汰算法吧
3.1新的Store
主要看看MemoryStore,在Store内部,有一个SelectableConcurrentHashMap,和ConcurrentHashMap很像,也是采用分段机制,但是他的淘汰机制好像非常不好,没有使用链表的形式,而是在所有元素中遍历,
//先找到要淘汰的个数
intevict = Math.min(map.quickSize() - maximumSize, MAX_EVICTION_RATIO);
for (inti = 0; i
//每次随机选出几个,再确定最应该淘汰的一个,效率不高removeElementChosenByEvictionPolicy(elementJustAdded);
}
public Element[] getRandomValues(finalintsize, Object keyHint) {
ArrayList sampled = new ArrayList(size * 2);
// pick a random starting point in the map
intrandomHash = rndm.nextInt();
finalintsegmentStart;
if (keyHint == null) {
segmentStart = (randomHash >>> segmentShift) & segmentMask;
} else {
segmentStart = (hash(keyHint.hashCode()) >>> segmentShift) & segmentMask;
}
intsegmentIndex = segmentStart;
do {
final HashEntry[] table = segments[segmentIndex].table;
finalinttableStart = randomHash & (table.length - 1);
inttableIndex = tableStart;
do {
for (HashEntry e = table[tableIndex]; e != null; e = e.next) {
Element value = e.value;
if (value != null && (!(e.pinned && elementPinningEnabled) || value.isExpired())) {
sampled.add(value);
}
}
if (sampled.size() >= size) {
return sampled.toArray(new Element[sampled.size()]);
}
//move to next table slot
tableIndex = (tableIndex + 1) & (table.length - 1);
} while (tableIndex != tableStart);
//move to next segment
segmentIndex = (segmentIndex + 1) & segmentMask;
} while (segmentIndex != segmentStart);
return sampled.toArray(new Element[sampled.size()]);
}
整了半天,貌似是为了随机定位到某个段,然后随机从某个元素开始遍历,直到找到指定个数的需要淘汰的数量,没仔细去想并发问题了,觉得效率比较低,不管了,还是
着重看下他的淘汰策略吧:
public Element selectedBasedOnPolicy(Element[] sampledElements, Element justAdded) {
//edge condition when Memory Store configured to size 0
if (sampledElements.length == 1) {
return sampledElements[0];
}
Element lowestElement = null;
for (Element element : sampledElements) {
if (element == null) {
continue;
}
if (lowestElement == null) {
if (!element.equals(justAdded)) {
lowestElement = element;
}
} else if (
compare(lowestElement,
element) && !element.equals(justAdded)) {
lowestElement = element;
}
}
return lowestElement;
}
LRU LFU FIFO的核心就在对compare的实现,
LRU:比较最后访问时间
public boolean compare(Element element1, Element element2) {
return element2.getLastAccessTime()
}
LFU:比较get次数(在get的时候会累加)
public boolean compare(Element element1, Element element2) {
return element2.getHitCount()
}
FIFO:创建/修改时间
public boolean compare(Element element1, Element element2) {
return element2.getLatestOfCreationAndUpdateTime() <
element1.getLatestOfCreationAndUpdateTime();
}
3.2老的LruMemoryStore
新的那种随机定位的方式让人感觉很怪,老的LRU实际使用的是SpoolingLinkedHashMap,
他在LinkedHashMap上增加了,他的put/get/remove是synchronized的,,所以没有并发安全性问题,但是感觉效率也不太高。。就是LinkedHashMap的同步版本了
4总结
没有发现啥亮点,代码太多了,看的几部分也没啥参考价值。。。。
java ehcache lru_ehcache缓存淘汰浅析相关推荐
- Java 常用缓存淘汰算法解析
前言 对于很多缓存中间件来说,内存是其操作的主战场,以redis来说,redis是很多互联网公司必备的选择,redis具有高效.简洁且易用的诸多特性被大家广泛使用,但我们知道,redis操作大多数属于 ...
- 基于Java实现本地缓存,缓存过期删除和LRU缓存淘汰
我们结合平常使用的Redis来想下,自己实现本地缓存需要考虑哪些因素呢,我这里总结了三点: 数据存储,基于Java实现的话我首先想到的是key-value结构的集合,如HashMap,并发环境下的话使 ...
- Java中用Ehcache做缓存处理
Java中用Ehcache做缓存处理 具体创建项目就不多说了.本例是的idea的maven项目中做的测试. 1 添加依赖 在pom.xml添加如下的依赖项 <dependency>< ...
- EhCache 分布式缓存/缓存集群
开发环境: System:Windows JavaEE Server:tomcat5.0.2.8.tomcat6 JavaSDK: jdk6+ IDE:eclipse.MyEclipse 6.6 开发 ...
- Ehcache分布式缓存及测试方法
接到配合架构部要求配合测试需求,对EhCache 进行测试,在此之前,未接触过ehcache缓存,之前知道一些缓存,但是还真没了解过内存缓存.于是百度,看书,查资料,先恶补一下ehcache的一些知识 ...
- Java本地高性能缓存的几种实现方式
Java缓存技术可分为远端缓存和本地缓存,远端缓存常用的方案有著名的redis和memcache,而本地缓存的代表技术主要有HashMap,Guava Cache,Caffeine和Encahche. ...
- Ehcache(缓存)
Ehcache(缓存) 一.什么是缓存 二.什么是Ehcache(缓存) 三.什么是cacheManager 四.ehcache.cacheManager和cache三者之间的关系 五.ehcache ...
- 一文深入了解史上最强的Java堆内缓存框架Caffeine
它提供了一个近乎最佳的命中率.从性能上秒杀其他一堆进程内缓存框架,Spring5更是为了它放弃了使用多年的GuavaCache 缓存,在我们的日常开发中用的非常多,是我们应对各种性能问题支持高并发的一 ...
- 看动画轻松理解「链表」实现「LRU缓存淘汰算法」
作者 | 程序员小吴,哈工大学渣,目前正在学算法,开源项目 「 LeetCodeAnimation 」5500star,GitHub Trending 榜连续一月第一. 本文为 AI科技大本营投稿文章 ...
最新文章
- android 的unregisterReceiver报错处理
- oracle 隐藏视图定义,【学习笔记】show hidden parameter 创建查看隐藏参数视图
- 2020-12-03 matlab 反馈函数 feedback
- soap方式的远程调用示例代码
- 图片上的文字怎么转换为word
- C#3.0新特性 和 Javascript
- 大数据_Flink_Java版_数据处理_流处理API_Sink操作_把数据存储到ElasticSearch---Flink工作笔记0040
- Three.js - 加载 .OBJ 格式模型(十六)
- Linux基础(三)
- 如何查看自己win10的产品密钥
- Resize的使用————Transforms
- SF18 | MACD顶底背离+动态区间交易模型源码(技术贴)
- 机器学习:深度信念网络(DBN)原理和实现
- FVCOM 环境基础配置(1) intel编译器 下载与安装
- 欢迎大家关注博主微信公众号
- IIS6.0功能及应用详解
- 【阅读】阅读软件Calibre以及电子书下载地址
- 利用halcon读取tiff图像,并且获取图像指针
- 企业微信网络抓包工具devtools_resources
- 2016年BYOD四大趋势
热门文章
- LVS简介及LVS-NAT负载均衡群集的搭建(要像记得回家的路一样记得理想和远方)
- 错误: 加载主类 时出现 LinkageError 解决办法
- F-6888 音频蓝牙模块应用笔记
- python文件二进制加密
- 【小白学java】java的面向对象设计:封装+继承+抽象类+接口(day06)
- Python实现多元线性回归方程梯度下降法与求函数极值
- 什么是图数据库neo4j是什么
- 神经网络的公式怎么计算,神经网络的公式有哪些
- 决策树算法——选择困难症的“良药”
- Wi-Fi 6强势来袭-更大容量 更低延迟 更快网速 更安全