最近要设计个缓存系统,所以到处看了看,简单看了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缓存淘汰浅析相关推荐

  1. Java 常用缓存淘汰算法解析

    前言 对于很多缓存中间件来说,内存是其操作的主战场,以redis来说,redis是很多互联网公司必备的选择,redis具有高效.简洁且易用的诸多特性被大家广泛使用,但我们知道,redis操作大多数属于 ...

  2. 基于Java实现本地缓存,缓存过期删除和LRU缓存淘汰

    我们结合平常使用的Redis来想下,自己实现本地缓存需要考虑哪些因素呢,我这里总结了三点: 数据存储,基于Java实现的话我首先想到的是key-value结构的集合,如HashMap,并发环境下的话使 ...

  3. Java中用Ehcache做缓存处理

    Java中用Ehcache做缓存处理 具体创建项目就不多说了.本例是的idea的maven项目中做的测试. 1 添加依赖 在pom.xml添加如下的依赖项 <dependency>< ...

  4. EhCache 分布式缓存/缓存集群

    开发环境: System:Windows JavaEE Server:tomcat5.0.2.8.tomcat6 JavaSDK: jdk6+ IDE:eclipse.MyEclipse 6.6 开发 ...

  5. Ehcache分布式缓存及测试方法

    接到配合架构部要求配合测试需求,对EhCache 进行测试,在此之前,未接触过ehcache缓存,之前知道一些缓存,但是还真没了解过内存缓存.于是百度,看书,查资料,先恶补一下ehcache的一些知识 ...

  6. Java本地高性能缓存的几种实现方式

    Java缓存技术可分为远端缓存和本地缓存,远端缓存常用的方案有著名的redis和memcache,而本地缓存的代表技术主要有HashMap,Guava Cache,Caffeine和Encahche. ...

  7. Ehcache(缓存)

    Ehcache(缓存) 一.什么是缓存 二.什么是Ehcache(缓存) 三.什么是cacheManager 四.ehcache.cacheManager和cache三者之间的关系 五.ehcache ...

  8. 一文深入了解史上最强的Java堆内缓存框架Caffeine

    它提供了一个近乎最佳的命中率.从性能上秒杀其他一堆进程内缓存框架,Spring5更是为了它放弃了使用多年的GuavaCache 缓存,在我们的日常开发中用的非常多,是我们应对各种性能问题支持高并发的一 ...

  9. 看动画轻松理解「链表」实现「LRU缓存淘汰算法」

    作者 | 程序员小吴,哈工大学渣,目前正在学算法,开源项目 「 LeetCodeAnimation 」5500star,GitHub Trending 榜连续一月第一. 本文为 AI科技大本营投稿文章 ...

最新文章

  1. android 的unregisterReceiver报错处理
  2. oracle 隐藏视图定义,【学习笔记】show hidden parameter 创建查看隐藏参数视图
  3. 2020-12-03 matlab 反馈函数 feedback
  4. soap方式的远程调用示例代码
  5. 图片上的文字怎么转换为word
  6. C#3.0新特性 和 Javascript
  7. 大数据_Flink_Java版_数据处理_流处理API_Sink操作_把数据存储到ElasticSearch---Flink工作笔记0040
  8. Three.js - 加载 .OBJ 格式模型(十六)
  9. Linux基础(三)
  10. 如何查看自己win10的产品密钥
  11. Resize的使用————Transforms
  12. SF18 | MACD顶底背离+动态区间交易模型源码(技术贴)
  13. 机器学习:深度信念网络(DBN)原理和实现
  14. FVCOM 环境基础配置(1) intel编译器 下载与安装
  15. 欢迎大家关注博主微信公众号
  16. IIS6.0功能及应用详解
  17. 【阅读】阅读软件Calibre以及电子书下载地址
  18. 利用halcon读取tiff图像,并且获取图像指针
  19. 企业微信网络抓包工具devtools_resources
  20. 2016年BYOD四大趋势

热门文章

  1. LVS简介及LVS-NAT负载均衡群集的搭建(要像记得回家的路一样记得理想和远方)
  2. 错误: 加载主类 时出现 LinkageError 解决办法
  3. F-6888 音频蓝牙模块应用笔记
  4. python文件二进制加密
  5. 【小白学java】java的面向对象设计:封装+继承+抽象类+接口(day06)
  6. Python实现多元线性回归方程梯度下降法与求函数极值
  7. 什么是图数据库neo4j是什么
  8. 神经网络的公式怎么计算,神经网络的公式有哪些
  9. 决策树算法——选择困难症的“良药”
  10. Wi-Fi 6强势来袭-更大容量 更低延迟 更快网速 更安全