Java 缓存介绍(Caffeine,EhCache)

Caffeine

一个高性能的缓存库,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类不同,可以根据自己的需求来选择合适的方式来加载数据

回收策略

  1. 基于maximumSize()设置的大小,若果超过最大值后将异步回收

  2. 基于权重大小删除元素

    1. .maximumWeight():指定缓存的最大容量,当缓存超出这个容量的时候,会使用Window TinyLfu策略来删除缓存
    2. .weighter((k,v)->{}):计算权重方法
    3. maximumWeight与maximumSize不可以同时使用。
  3. 基于时间回收

    1. 访问后到期 — 从上次读或写发生后,条目即过期
    2. 写入后到期 — 从上次写入发生之后,条目即过期
    3. 自定义策略 — 到期时间由 Expiry 实现独自计算
  4. 基于引用

    我们可以将缓存的驱逐配置成基于垃圾回收器。为此,我们可以将key 和 value 配置为弱引用或只将值配置成软引用。

    • Caffeine.weakKeys():使用弱引用存储key。如果没有其他地方对该key有强引用,那么该缓存就会被垃圾回收器回收。
    • Caffeine.weakValues():使用弱引用存储value。
    • Caffeine.softValues():使用软引用存储value。当内存满了过后,软引用的对象以将使用最近最少使用(least-recently-used ) 的方式进行垃圾回收。

Ehcache

​ Ehcache 从 Hibernate 发展而来,逐渐涵盖了 Cahce 界的全部功能,是目前发展势头最好的一个项目。具有快速,简单,低消耗,依赖性小,扩展性强,支持对象或序列化缓存,支持缓存或元素的失效,提供 LRU、LFU 和 FIFO 缓存策略,支持内存缓存和磁盘缓存,分布式缓存机制等等特点。

功能

  • 支持内存及磁盘存储
  • 多种缓存策略
  • 支持多缓存管理器实例,以及一个实例的多个缓存区域

缓存淘汰策略

  • FIFO:先进先出
  • LFU:最少被使用,缓存的元素有一个hit属性,hit值最小的将会被清出缓存
  • LRU:最近最少使用,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存

依赖

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);
    }
}

2种缓存框架对比

特性

​ 从支持的功能上来看,ehcache支持的功能特性更多一些,比如多级缓存,分布式缓存,缓存监听器等等。但如果只是想简单的使用一个内存缓存组件,并且对性能有较高的要求时,可以优先考虑Caffeine,它的性能比ehcache更好,并且它使用了更加优秀的缓存淘汰策略,提供接近理想的命中率,在Spring5中已经作为基础的缓存组件使用了。

易用性

​ 从我简单使用上来看,Caffeine提供的api更友好一些,而且ehcache似乎没有提供异步加载特性。配置也略微烦琐了些。

性能

1 读多写少场景

测试条件

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
2 只读场景

测试条件

1.缓存1000个数据

2.10个线程读

Caffeine(读) Ehcache(读)
1 1723628225 2129962082
2 1899030885 2025097805
3 2124612664 2086497546
平均 1915757258 2080519144

只读场景下Caffeine性能比Ehcache略微差一些。

总结

​ 在读性能上两者差距不大,但在写性能上Caffeine明显比Ehcache要高出不少。综合易用性,性能来看,我认为一般项目使用Caffeine就足够了。

你可能感兴趣的:(Java 缓存介绍(Caffeine,EhCache))