一个高性能的缓存库,Caffeine 使用 Window TinyLfu 回收策略,可以提供了一个近乎最佳的命中率。
maven
com.github.ben-manes.caffeine
caffeine
2.5.5
Grade
compile 'com.github.ben-manes.caffeine:caffeine:2.5.5'
@Test
public void baseTest() {
Cache<String, Data> cache = Caffeine.newBuilder()
// 设置过期时间
.expireAfterWrite(1, TimeUnit.MINUTES)
// 缓存数量
.maximumSize(100).build();
// 往缓存中设置
cache.put("A", new Data("A"));
Assert.assertEquals(cache.getIfPresent("A").getData(), "A");
// 取值 若存在返回 不存在返回null
Data b = cache.getIfPresent("B");
Assert.assertNull(b);
// 取值 若不存在 则按后面计算并返回
b = cache.get("B", k -> new Data(k));
Assert.assertEquals(cache.getIfPresent("B").getData(), "B");
// 手动移除key
cache.invalidate("A");
Assert.assertNull(cache.getIfPresent("A"));
}
@Test
public void syncLoadTest() {
LoadingCache<String, Data> cache = Caffeine.newBuilder()
.maximumSize(100)
.expireAfterWrite(1, TimeUnit.MINUTES)
.build(k -> new Data(k));
//这个获取的仍然为空
Assert.assertNull(cache.getIfPresent("A"));
// get() 检索值 此处会根据初始化时指定的方法初始化value
Data a = cache.get("a");
Assert.assertNotNull(a);
Assert.assertEquals(a.getData(),"a");
}
@Test
public void asyncLoadTest() {
AsyncLoadingCache<String, Data> cache = Caffeine.newBuilder().maximumSize(100).expireAfterWrite(1, TimeUnit.MINUTES).buildAsync(k -> new Data(k));
cache.get("A").thenAccept(data -> {
Assert.assertNotNull(data);
Assert.assertEquals(data.getData(), "a");
});
}
这3种加载方式使用的Cache类不同,可以根据自己的需求来选择合适的方式来加载数据
基于maximumSize()设置的大小,若果超过最大值后将异步回收
基于权重大小删除元素
基于时间回收
基于引用
我们可以将缓存的驱逐配置成基于垃圾回收器。为此,我们可以将key 和 value 配置为弱引用或只将值配置成软引用。
Ehcache 从 Hibernate 发展而来,逐渐涵盖了 Cahce 界的全部功能,是目前发展势头最好的一个项目。具有快速,简单,低消耗,依赖性小,扩展性强,支持对象或序列化缓存,支持缓存或元素的失效,提供 LRU、LFU 和 FIFO 缓存策略,支持内存缓存和磁盘缓存,分布式缓存机制等等特点。
maven
org.ehcache
ehcache
3.7.0
gradle
compile 'org.ehcache:ehchache:3.7.0'
public class EhCache implements LocalCache {
private CacheManager cacheManager;
private Cache cache;
public EhCache() {
// 创建缓存管理器 一个缓存管理器可以关联多个缓存
cacheManager = CacheManagerBuilder.newCacheManagerBuilder().build();
// 初始化
cacheManager.init();
// 创建 dataCache缓存
CacheConfigurationBuilder builder = CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class, Data.class, ResourcePoolsBuilder.heap(100));
cache = cacheManager.createCache("dataCache", builder);
}
@Override
public Data get(String K) {
return cache.get(K);
}
@Override
public void set(String K, Data data) {
cache.put(K, data);
}
}
从支持的功能上来看,ehcache支持的功能特性更多一些,比如多级缓存,分布式缓存,缓存监听器等等。但如果只是想简单的使用一个内存缓存组件,并且对性能有较高的要求时,可以优先考虑Caffeine,它的性能比ehcache更好,并且它使用了更加优秀的缓存淘汰策略,提供接近理想的命中率,在Spring5中已经作为基础的缓存组件使用了。
从我简单使用上来看,Caffeine提供的api更友好一些,而且ehcache似乎没有提供异步加载特性。配置也略微烦琐了些。
测试条件
1.缓存1000个数据
2.8个线程读 2个线程写
Caffeine(读/写) | Ehcache(读/写) | |
---|---|---|
1 | 1558360022/184773156 | 1794188434/155912462 |
2 | 1861119523/288443676 | 1818122432/147250831 |
3 | 1421957913/277856668 | 1348268819/142143289 |
平均 | 1613812486/250357833 | 1653526561/148435527 |
测试条件
1.缓存1000个数据
2.10个线程读
Caffeine(读) | Ehcache(读) | |
---|---|---|
1 | 1723628225 | 2129962082 |
2 | 1899030885 | 2025097805 |
3 | 2124612664 | 2086497546 |
平均 | 1915757258 | 2080519144 |
只读场景下Caffeine性能比Ehcache略微差一些。
在读性能上两者差距不大,但在写性能上Caffeine明显比Ehcache要高出不少。综合易用性,性能来看,我认为一般项目使用Caffeine就足够了。