轻量级Java对象缓存API

100

问题

我正在寻找一个Java内存对象缓存API。有什么推荐的吗?你过去使用过哪些解决方案?

现状

目前,我只是在使用一个Map:

Map cache = new HashMap<String, Object>();
cache.put("key", value);

需求

我需要扩展缓存以包括基本功能,如:

  • 最大大小
  • 生存时间

但是,我不需要更复杂的功能,如:

  • 从多个进程访问(缓存服务器)
  • 持久性(到磁盘)

建议

内存中缓存:

  • Guava CacheBuilder - 活跃开发。请参阅这个演示文稿
  • LRUMap - 通过API配置。没有TTL。不是专门为缓存构建的。
  • whirlycache - XML配置。邮件列表。上次更新于2006年。
  • cache4j - XML配置。俄语文档。上次更新于2006年。

企业级缓存:

  • JCS - 属性配置。广泛的文档。
  • Ehcache - XML配置。广泛的文档。根据Google搜索结果,迄今为止最受欢迎的。

3
你能否编辑“内存缓存建议”一节,加入Guava Cache呢?我像你一样正在寻找轻量级的缓存机制,发现了这个问题,但是没有找到Guava Cache,因为它在下面。现在我使用guava cache包,真是太神奇了。 - andras
1
完成。 :-) 很高兴你喜欢它! - Kevin Bourrillion
也许你还想考虑添加相对较新的cache2k。在他们的基准测试页面上,它被称为比ehcache和Guava性能更好。 - user3001
尝试使用jcabi-aspects中的@Cacheable:http://www.yegor256.com/2014/08/03/cacheable-java-annotation.html - yegor256
7个回答

58

EHCache很好用。您可以创建一个内存缓存。查看他们的代码示例以了解如何创建内存缓存。您可以指定最大大小和生存时间。

EHCache提供了一些高级功能,但如果您不想使用它们,请不要使用。但知道它们的存在是很好的,以防您的要求发生变化。

以下是通过代码创建的内存缓存,无需配置文件。

CacheManager cacheManager = CacheManager.getInstance();
int oneDay = 24 * 60 * 60;
Cache memoryOnlyCache = new Cache("name", 200, false, false, oneDay, oneDay);
cacheManager.addCache(memoryOnlyCache);
创建一个缓存,可容纳200个元素,并且具有24小时的ttl。

2
EHCache是只引用对象还是会序列化和反序列化对象呢? - Phương Nguyễn
2
EHCache是一种重量级的解决方案吗?我们正在研究现有的缓存解决方案,以在Android上实现API缓存。 - mxk
2
它对于Android来说太重了。我正在使用Kitty缓存,它非常完美! - Felipe
@Stevet K,我晚了解到这个缓存技术,但我猜getInstance()已经被删除或更改了。 - Menai Ala Eddine - Aladdin

47

我非常喜欢使用附带MapMakerGoogle Guava (API)。

JavaDoc提供了一个相当不错的示例,展示了它易用性和强大功能:

ConcurrentMap<Key, Graph> graphs = new MapMaker()
   .concurrencyLevel(32)
   .softKeys()
   .weakValues()
   .expiration(30, TimeUnit.MINUTES)
   .makeComputingMap(
       new Function<Key, Graph>() {
         public Graph apply(Key key) {
           return createExpensiveGraph(key);
         }
       });
此外,Guava 10.0版引入了更为广泛的 com.google.common.cache(这里有一篇详细介绍如何使用它们的wiki条目)。

Guava用户指南:缓存解释。请参阅链接:https://github.com/google/guava/wiki/CachesExplained - mx1up
@mxttie:谢谢,我已经添加了链接,如果有类似的补充,请随意提出建议。 - Joachim Sauer

10

1
不错,但如果它有TTL就更好了。 - Rosdi Kasim
谢谢!正好是我在打之前想检查一下是否有人已经开源了这个东西 :) - jpillora
@RosdiKasim 实际上在 put() 调用时有 TTL,例如:cache.put("mykey", value, 500); 其中的 500 就是 TTL。 - Travis Reeder
1
@TravisR 嗯...,那时候它没有 TTL.. :p - Rosdi Kasim
啊,没意识到那个评论是多久之前的了。 - Travis Reeder

9
您可以使用LinkedHashMap实现一个简单的缓存而无需第三方jar包:
    Map <String, Foo> cache = new LinkedHashMap<String, Foo>(MAX_ENTRIES + 1, .75F, true) {

        public boolean removeEldestEntry(Map.Entry<String, Foo> eldest) {
            return size() > MAX_ENTRIES;
        }
    };

然后您可以像这样从缓存中获取:

然后你可以像这样从缓存中获取

    Foo foo = cache.get(key);
    if (foo == null && !cache.containsKey(key)) {
        try {
            FooDAO fooDAO = DAOFactory.getFooDAO(conn);
            foo = fooDAO.getFooByKey(key);
            cache.put(key, foo);
        } catch (SQLException sqle) {
            logger.error("[getFoo] SQL Exception when accessing Foo", sqle);
        }
    }

其余部分留给读者作为练习 :)


2
我认为这种方法没有TTL容量。不过,这是开始自己开发的好方法。 - Chase Seibert
是的,我会把TTL的部分留作读者练习的一部分 :p - 当然第三方库已经比自己编写的进行了更多的测试。 - JeeBee

9

5

JCS是经过验证的。尽管它在缓存机制方面很轻,但您可以深入了解实际代码,并模仿HashMap在其内部执行的操作,以精确地满足您的需求,而不会超出范围。您似乎对自己想要什么有一个相当好的想法。


我猜你的意思是它在缓存机制方面轻便?尽管如此,它似乎是最受欢迎的企业解决方案之一。 - Chase Seibert

3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接