CLOVER🍀

That was when it all began.

Javaで使えるオープンソース・キャッシュライブラリ

最近は、仕事でEhcacheを使っていたり、他にも調べたりすることがあったので、ちょっとJavaで使えるオープンソースなキャッシュライブラリについてまとめてみることにしました。

あ、そんなに大した内容ではないので、ご期待なさらぬよう…。

でまあ、改めて調べてみた感想としては、Ehcacheが現状デファクトになっていることが改めてわかった感じですね。Javaのキャッシュライブラリって、そこそこ数が見つかるんですけど、開発が止まってしまっているものが多かったり、ドキュメントも全然ないというものもけっこう多くて、割とカオス…。

しかも、軽量で気軽に導入できるキャッシュライブラリって、今はない感じですね。Guavaがキャッシュだけで独立していれば…。EhcacheとかInfinispanだと、機能で困ることはないと思いますが、ちょいと大きいですよね。

調べる時に気になるのは、以下のようなところでしょうか。

名称 ライセンス 最新安定版 アイドル時間による有効期限(idleTime) エントリ自体の有効期限(TTL) オフィシャルサイトURL
Eviction有りの場合のアルゴリズム ディスクなどへの保存 Maven Centralへの登録 ドキュメント JSR-107対応

各ライブラリのバージョンは、2013/7/23時点のものです。

性能に関しては、調べてません。そのライブラリ自身が公開しているパフォーマンス測定結果とかは、ちょこちょこ見てますが。

代わりに、個人的に興味のあるライブラリは、簡単なソースを用意しました。

情報収集のとっかかりは、このあたりになります。
http://stackoverflow.com/questions/230649/lightweight-java-object-cache-api
http://java-source.net/open-source/cache-solutions

あと、Java EE 7では導入は見送られましたが、Javaのキャッシュの標準APIとして、JSR-107があります。

詳細は、こちらに。
https://github.com/jsr107/jsr107spec

Java EE 8では入るといいですね。

一応、Reference Implementationもありますが、商用環境で使っちゃダメですよ。
https://github.com/jsr107/RI

では、いってみましょう。

Ehcache

ご存知、Javaのキャッシュライブラリの代表選手。

キャッシュエントリのディスクへの保存、レプリケーション、トランザクション、イベントリスナなどかなり高機能で、だいたいこれを選んでおけば、間違いはなかろうかと…。オフィシャルサイトのドキュメントも、かなり充実しています。

Javaの標準キャッシングAPI、JSR-107の実装でもあります。

名称 ライセンス 最新安定版 アイドル時間による有効期限(idleTime) エントリ自体の有効期限(TTL) オフィシャルサイトURL
Ehcache OSS版はApache License 2.0 2.7.2 (2013/7/2) ○ ○ http://ehcache.org/
Eviction有りの場合のアルゴリズム ディスクなどへの保存 Maven Centralへの登録 ドキュメント JSR-107対応
LRU, LFU, FIFO ○ ○ ○ ○

商用版は、現在BigMemory Maxという名前の製品らしいです。分散キャッシュ、キャッシュの容量制限なし、off-heapなど、さらにいろいろ高機能になります。

普通に使う分には、オープンソース版で困ることはないと思いますが。日本語での情報も、それなりに見つけやすいと思いますので。

では、コード例を。

Mavenの設定。

    <dependency>
      <groupId>net.sf.ehcache</groupId>
      <artifactId>ehcache</artifactId>
      <version>2.7.2</version>
    </dependency>

設定ファイルのサンプル。

<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
  <diskStore path="java.io.tmpdir"/>
  <defaultCache
     maxEntriesLocalHeap="10000"
     eternal="false"
     timeToIdleSeconds="120"
     timeToLiveSeconds="120"
     maxEntriesLocalDisk="10000000"
     diskExpiryThreadIntervalSeconds="120"
     memoryStoreEvictionPolicy="LRU">
    <persistence strategy="localTempSwap" />
  </defaultCache>

  <cache name="memoryCache"
     maxEntriesLocalHeap="100"
     eternal="false"
     timeToIdleSeconds="3"
     timeToLiveSeconds="6"
     memoryStoreEvictionPolicy="LFU">
    <persistence strategy="none" />
  </cache>
</ehcache>

コードのサンプル。

package caching.ehcache;

import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
import net.sf.ehcache.config.CacheConfiguration;

public class EhcacheExample {
    public static void main(String[] args) {
        CacheManager cacheManager = CacheManager.newInstance(
            EhcacheExample.class.getResourceAsStream("/ehcache.xml"));
        // 設定ファイルの名前が「ehcache.xml」で、クラスパス上にある場合は以下でもOK
        // CacheManager cacheManager = CacheManager.newInstance();

        try {
            // Ehcacheの場合は、defaultの定義を元にキャッシュを作成する場合は
            // 別途Cacheのインスタンスを作成して、CacheManager#addCacheを呼び出す必要がある
            CacheConfiguration defaultCacheConfiguration
                = cacheManager.getConfiguration().getDefaultCacheConfiguration().clone();

            defaultCacheConfiguration.setName("defaultCache");
            cacheManager.addCache(new Cache(defaultCacheConfiguration));

            Cache defaultCache = cacheManager.getCache("defaultCache");

            // 個別に設定したcache
            Cache cache = cacheManager.getCache("memoryCache");

            // キャッシュへのへのエントリの登録
            Element putEntry = new Element("key1", "value1");
            cache.put(putEntry);
            
            cache.put(new Element("key2", "value2"));

            // キャッシュからのエントリの取得
            Element getElement = cache.get("key1");
            String getValue = (String) getElement.getObjectValue();
            System.out.println(getValue);

            // キャッシュからのエントリの削除
            cache.remove("key1");

            // キャッシュからのエントリの全削除
            cache.removeAll();

            // Expireの確認
            cache.put(new Element("key3", "value3"));
            cache.put(new Element("key4", "value4"));

            try { Thread.sleep(2 * 1000L); } catch (InterruptedException e) { }

            // ひとつだけ、アクセス
            System.out.println(cache.get("key3") != null);

            try { Thread.sleep(2 * 1000L); } catch (InterruptedException e) { }

            // アクセスしたエントリのみ、キャッシュに残ったまま
            System.out.println(cache.get("key3") != null);
            System.out.println(cache.get("key4") == null);

            try { Thread.sleep(7 * 1000L); } catch (InterruptedException e) { }

            // もうひとつのエントリも、有効期限が切れる
            System.out.println(cache.get("key3") == null);
            System.out.println(cache.get("key4") == null);
        } finally {
            cacheManager.shutdown();
        }
    }
}

Guava Cache

GoogleのライブラリであるGuavaに、キャッシュ用のパッケージが含まれていてこちらも比較的軽量なキャッシュライブラリとして紹介されるようですので。

ドキュメントはWikiに、基本的なことがそこそこ書いてある感じです。まあ、あとは触って慣れれば困らない気もしますが。

あと、PDFでの資料もあります。
http://guava-libraries.googlecode.com/files/JavaCachingwithGuava.pdf

名称 ライセンス 最新安定版 アイドル時間による有効期限(idleTime) エントリ自体の有効期限(TTL) オフィシャルサイトURL
Guava Apache License 2.0 14.0.1(2013/3/15) ○ ○ https://code.google.com/p/guava-libraries/
Eviction有りの場合のアルゴリズム ディスクなどへの保存 Maven Centralへの登録 ドキュメント JSR-107対応
サイズ, 時間、重み付け × ○ ○ ×

Ehcacheのように、エントリのディスクへの保存みたいな機能はありません。後述のLoadingCacheを使えば、頑張れるかもしれませんが…。設定も、APIで組み立てるか文字列ベースでパースをかけるかの2通りの方法がありますが、明示的な設定ファイルの機構などはないみたいです。

それから、Betaアノテーションが付いていると、そのクラスはBeta版だということなのですが、それだとほとんどのクラスがBeta版なんですけど…。

あと、キャッシュ単体の機能としてはすごくシンプルですが、これを持ってくるとその他のGuavaのCollectionやらFunctionやらの各種ライブラリが付いてくるので、結果としてすごくいろいろライブラリとして取り込むことになってしまいます。

Mavenの設定。

    <dependency>
      <groupId>com.google.guava</groupId>
      <artifactId>guava</artifactId>
      <version>14.0.1</version>
    </dependency>

コードのサンプル。

package caching.guava;

import java.util.concurrent.TimeUnit;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;

public class GuavaCacheExample {
    public static void main(String[] args) {
        Cache<String, String> cache =
            CacheBuilder.newBuilder()
            .maximumSize(100)
            .expireAfterAccess(3, TimeUnit.SECONDS)
            .expireAfterWrite(6, TimeUnit.SECONDS)
            .build();

        // 上記設定を、文字列で指定することも可能
        // String spec = "maximumSize=100,expireAfterAccess=3s,expireAfterWrite=6s";
        // Cache<String, String> cache = CacheBuilder.from(spec).build();

        // キャッシュへのへのエントリの登録
        cache.put("key1", "value1");
        cache.put("key2", "value2");

        // キャッシュからのエントリの取得
        String value = cache.getIfPresent("key1");
        System.out.println(value);

        // キャッシュからのエントリの削除
        cache.invalidate("key1");

        // キャッシュからのエントリの全削除
        cache.invalidateAll();

        // Expireの確認
        cache.put("key3", "value3");
        cache.put("key4", "value4");

        try { Thread.sleep(2 * 1000L); } catch (InterruptedException e) { }

        // ひとつだけ、アクセス
        System.out.println(cache.getIfPresent("key3") != null);

        try { Thread.sleep(2 * 1000L); } catch (InterruptedException e) { }

        // アクセスしたエントリのみ、キャッシュに残ったまま
        System.out.println(cache.getIfPresent("key3") != null);
        System.out.println(cache.getIfPresent("key4") == null);

        try { Thread.sleep(7 * 1000L); } catch (InterruptedException e) { }

        // もうひとつのエントリも、有効期限が切れる
        System.out.println(cache.getIfPresent("key3") == null);
        System.out.println(cache.getIfPresent("key4") == null);
    }
}

Guavaのキャッシュで面白いのは、LoadingCacheというのがあって、キャッシュからgetを行ってエントリがなかった時にキャッシュ側に対象のデータをロードする機能があります。

そのサンプルです。以下のコードは、2つのキーに対してそれぞれ2回getしています。取得対象のデータはsleepをかけているため重いのですが、1回目のgetでキャッシュにデータも入るため、2回目の呼び出しは高速に行われます。

package caching.guava;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

import com.google.common.cache.LoadingCache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;

public class GuavaLoadingCacheExample {
    private static String getValue(String k) {
        try {
            Thread.sleep(2 * 1000L);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        return "value" + k.substring(k.length() - 1);
    }

    public static void main(String[] args) {
        LoadingCache<String, String> cache =
            CacheBuilder.newBuilder()
            .maximumSize(100)
            .expireAfterAccess(3, TimeUnit.SECONDS)
            .expireAfterWrite(6, TimeUnit.SECONDS)
            .build(new CacheLoader<String, String>() {
                    public String load(String key) throws Exception {
                        System.out.println("Load Key => " + key);
                        return getValue(key);
                    }
                });

        // キャッシュへのエントリのロードと取得を、同時に行う
        try {
            String value1 = cache.get("key1");
            System.out.println(value1);
            String value2 = cache.get("key2");
            System.out.println(value2);

            value1 = cache.get("key1");
            System.out.println(value1);
            value2 = cache.get("key2");
            System.out.println(value2);
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

JCS(Java Caching System)

Apache Software Foundationのキャッシュライブラリです。開発版は2.0-SNAPSHOTなのですが、これ、どういう状況なんでしょう。

JCS自体は、Ehcacheに見劣りしない高機能なキャッシュライブラリです。

名称 ライセンス 最新安定版 アイドル時間による有効期限(idleTime) エントリ自体の有効期限(TTL) オフィシャルサイトURL
JCS Apache License 2.0 1.3(2007/7/7) ○ ○ http://commons.apache.org/proper/commons-jcs/
Eviction有りの場合のアルゴリズム ディスクなどへの保存 Maven Centralへの登録 ドキュメント JSR-107対応
FIFO, LRU, MRU ○ ○ ○ ×

ドキュメントはまあまあ。検索しても、それなりに情報は見つけることができます。

ですが、最新の安定版は2007年の1.3ですし、JDK 1.3でコンパイルされているという相当古いものなので、今これを選ぶ理由はなさそうですね…。これを使うなら、Ehcacheを使うでしょう。

Mavenの設定。

    <dependency>
      <groupId>org.apache.jcs</groupId>
      <artifactId>jcs</artifactId>
      <version>1.3</version>
    </dependency>

設定ファイルのサンプル。「cache.ccf」という名前で作ります。
*アイドル状態による有効期限切れ確認のため、ShrinkerIntervalSecondsをめっちゃ短くしてます

# DEFAULT CACHE REGION

jcs.default=
jcs.default.cacheattributes=org.apache.jcs.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=10000
jcs.default.cacheattributes.MemoryCacheName=org.apache.jcs.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.cacheattributes.UseMemoryShrinker=true
jcs.default.cacheattributes.UseMemoryShrinker=true
jcs.default.cacheattributes.ShrinkerIntervalSeconds=2
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLifeSeconds=120


jcs.region.small=
jcs.region.small.cacheattributes=org.apache.jcs.engine.CompositeCacheAttributes
jcs.region.small.cacheattributes.MaxObjects=10000
jcs.region.small.cacheattributes.MemoryCacheName=org.apache.jcs.engine.memory.lru.LRUMemoryCache
jcs.region.small.cacheattributes.UseMemoryShrinker=true
jcs.region.small.cacheattributes.ShrinkerIntervalSeconds=2
jcs.region.small.cacheattributes.MaxMemoryIdleTimeSeconds=3
jcs.region.small.elementattributes.IsEternal=false
jcs.region.small.elementattributes.MaxLifeSeconds=6

コードのサンプル。

package caching.jcs;

import org.apache.jcs.JCS;
import org.apache.jcs.access.exception.CacheException;

public class JcsExample {
    public static void main(String[] args) {
        try {
            // デフォルトの定義を元に作成した、JCSのインスタンス 
            JCS defaultJcs = JCS.getInstance("default");
            // 個別に設定したJCSのインスタンス
            JCS smallJcs = JCS.getInstance("small");

            // キャッシュへのへのエントリの登録
            smallJcs.put("key1", "value1");
            smallJcs.put("key2", "value2");

            // キャッシュからのエントリの取得
            String value = (String) smallJcs.get("key1");
            System.out.println(value);

            // キャッシュからのエントリの削除
            smallJcs.remove("key1");

            // キャッシュからのエントリの全削除
            smallJcs.clear();

            // Expireの確認
            smallJcs.put("key3", "value3");
            smallJcs.put("key4", "value4");

            try { Thread.sleep(2 * 1000L); } catch (InterruptedException e) { }

            // ひとつだけ、アクセス
            System.out.println(smallJcs.get("key3") != null);

            try { Thread.sleep(2 * 1000L); } catch (InterruptedException e) { }

            // アクセスしたエントリのみ、キャッシュに残ったまま
            System.out.println(smallJcs.get("key3") != null);
            System.out.println(smallJcs.get("key4") == null);

            try { Thread.sleep(7 * 1000L); } catch (InterruptedException e) { }

            // もうひとつのエントリも、有効期限が切れる
            System.out.println(smallJcs.get("key3") == null);
            System.out.println(smallJcs.get("key4") == null);

            defaultJcs.dispose();
            smallJcs.dispose();
        } catch (CacheException e) {
            e.printStackTrace();
        }
    }
}

Apache DirectMemory

ASFにある、ちょっと変わったキャッシュライブラリ。2012/7/7に0.1-incubatorがリリースされた、比較的新しいキャッシュライブラリ。もともと、Github上で作られていたものが、ASFに移ってきたものみたいです。

このライブラリが変わっているのは、off-heapメモリを前面に出しているところですね。NIOのByteBuffer.allocateDirectで確保する、JavaVMヒープ外のメモリをキャッシュに使用します。

ヒープ内のキャッシュと比べて、GCの影響を受けない利点がありますが、シリアライズ/デシリアライズのコストがかかるというトレードオフですね。

資料もあるみたいです。
http://www.slideshare.net/benoitperroud/direct-memory-jugl20120308-12607297

キャッシュライブラリでoff-heapの機能を持つものはTerracottaだったり、Hazelcastだったりとでありますが、その機能は商用ライセンスだったりするので、これを正面に出しているというところはちょっと面白いです。

むしろ、普通のヒープ上で管理するキャッシュがありません…。

名称 ライセンス 最新安定版 アイドル時間による有効期限(idleTime) エントリ自体の有効期限(TTL) オフィシャルサイトURL
Apache DirectMemory Apache License 2.0 なし(0.1-incubatingは2012/7/9 × ○ http://directmemory.apache.org/
Eviction有りの場合のアルゴリズム ディスクなどへの保存 Maven Centralへの登録 ドキュメント JSR-107対応
なし × ○ × ×

オフィシャルサイトもただ存在するだけですし、ドキュメントも皆無、機能的にもちょっと少な過ぎ?という感じなので、ちょっと使える状態ではなさそうです。

アプローチとしては、興味があったので、今回取り上げてみました。

開発中の0.2では、設定ファイルの導入、sun.misc.Unsafeを使ったメモリアロケータ、Solr、Ehcache、Guavaとかと関連しそうなパッケージとかが入ってましたが、今後はどうなることやら…。

今回は、0.1-incubatingを使ったサンプルを載せます。今後いろいろ変更が入ると思うので、全然参考にならない気がしますが(笑)。

Mavenの設定。

    <dependency>
      <groupId>org.apache.directmemory</groupId>
      <artifactId>directmemory-cache</artifactId>
      <version>0.1-incubating</version>
    </dependency>

コードのサンプル。

package caching.directmemory;

import org.apache.directmemory.DirectMemory;
import org.apache.directmemory.cache.CacheService;
import org.apache.directmemory.measures.Ram;
import org.apache.directmemory.memory.Pointer;

public class DirectMemoryExample {
    public static void main(String[] args) {
        CacheService<String, String> cache =
            new DirectMemory<String, String>()
            .setNumberOfBuffers(4)
            .setInitialCapacity(100)
            .setSize(Ram.Mb(1))
            .setDisposalTime(3)  // 有効期限の切れたエントリのチェック間隔
            .newCacheService();

        // cache.scheduleDisposalEvery(1000L);

        // キャッシュへのへのエントリの登録
        cache.put("key1", "value1");
        cache.put("key2", "value2");

        // キャッシュからのエントリの取得
        String value = cache.retrieve("key1");
        System.out.println(value);

        // キャッシュからのエントリの全削除
        cache.clear();

        // Expireの確認
        cache.put("key3", "value3", 3 * 1000);  // 有効期限を設定したい場合は、第3引数に指定する
        cache.put("key4", "value4", 3 * 1000);

        try { Thread.sleep(2 * 1000L); } catch (InterruptedException e) { }

        // ひとつだけ、アクセス
        System.out.println(cache.retrieve("key3") != null);

        try { Thread.sleep(2 * 1000L); } catch (InterruptedException e) { }

        // アクセスする、しないに関わらず、両方共有効期限切れになります
        // *アクセスによる、有効期限の延長は行われない
        System.out.println(cache.retrieve("key3") == null);
        System.out.println(cache.retrieve("key4") == null);

        // 正しい終了の方法がわかりません…
        // 0.2では、CacheServiceにcloseメソッドが入っているようですが…
        System.exit(0);
    }
}

このライブラリの、正しい終了の仕方がわかりません。何もしないとスレッドが残ってしまいます…。0.2では、コメントにもあるようにCacheServiceにcloseメソッドが追加されているので、こちらを使えばいいのかな?

Infinispan

このブログでもバシバシ書いているライブラリで、単なるキャッシュというよりは、In Memory Data Gridという位置付けなのですが、JSR-107の実装でもあるので載せることにしました。JBoss Cacheの後継です。

まあ、これ出しちゃうとHazelcastとかどーなのよ?とかいう話もあるかと思いますが…。

で、キャッシュとして見た時は、Ehcacheに負けず劣らずの高機能なキャッシュライブラリとなります。ドキュメントもそこそこ充実していますが、日本語の情報は少ないです。

商用版は、InfinispanをコアにしたJBoss Data Gridという製品ですが、どの辺が異なるのかはちょっと調べてないです…。

名称 ライセンス 最新安定版 アイドル時間による有効期限(idleTime) エントリ自体の有効期限(TTL) オフィシャルサイトURL
Infinispan LGPL 2.1(6.0.0以降は、Apache License 2.0) 5.3.0.Final(2013/6/25) ○ ○ http://www.jboss.org/infinispan
Eviction有りの場合のアルゴリズム ディスクなどへの保存 Maven Centralへの登録 ドキュメント JSR-107対応
LIRS, LRU ○ ○* ○ ○

*ただし、JBossのMavenリポジトリも参照する必要あり

見かけるベンチマークでは、Ehcacheよりも書き込みが遅くて読み込みが速いということになっていますが、情報量と知名度では及ばないと思うので、キャッシュライブラリとしては今のところEhcacheを抑えてInfinispanを薦める、強い理由はないですね…。

今回は、Data Gridではなく、JavaVM内で使用するキャッシュのサンプルとしてコード例を載せます。

Mavenの設定。

<!-- 要リポジトリ追加 -->
  <repositories>
    <repository>
      <id>jboss-public-repository-group</id>
      <name>JBoss Public Maven Repository Group</name>
      <url>http://repository.jboss.org/nexus/content/groups/public-jboss/</url>
    </repository>
  </repositories>

<!-- 依存関係 -->
    <dependency>
      <groupId>org.infinispan</groupId>
      <artifactId>infinispan-core</artifactId>
      <version>5.3.0.Final</version>
    </dependency>

設定ファイルのサンプル。

<?xml version="1.0" encoding="UTF-8"?>
<infinispan
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="urn:infinispan:config:5.3 http://www.infinispan.org/schemas/infinispan-config-5.3.xsd"
    xmlns="urn:infinispan:config:5.3">

  <default>
    <eviction maxEntries="10000" strategy="LIRS" />
    <expiration lifespan="120000" maxIdle="120000" />
  </default>

  <namedCache name="smallCache">
    <eviction maxEntries="100" strategy="LIRS" />
    <expiration lifespan="6000" maxIdle="3000" />
  </namedCache>

</infinispan>

コードのサンプル。

package caching.infinispan;

import java.io.IOException;

import org.infinispan.Cache;
import org.infinispan.manager.DefaultCacheManager;
import org.infinispan.manager.EmbeddedCacheManager;

public class InfinispanExample {
    public static void main(String[] args) {
        EmbeddedCacheManager manager = null;
        Cache<String, String> defaultCache = null;
        Cache<String, String> smallCache = null;

        try {
            manager = new DefaultCacheManager("infinispan.xml");

            // defaultの定義を元に作成した、Cacheのインスタンス
            defaultCache = manager.getCache();

            // 個別に設定したcache
            smallCache = manager.getCache("smallCache");

            // キャッシュへのへのエントリの登録
            smallCache.put("key1", "value1");
            smallCache.put("key2", "value2");

            // キャッシュからのエントリの取得
            String value = smallCache.get("key1");
            System.out.println(value);

            // キャッシュからのエントリの削除
            smallCache.remove("key1");

            // キャッシュからのエントリの全削除
            smallCache.clear();

            // Expireの確認
            smallCache.put("key3", "value3");
            smallCache.put("key4", "value4");

            try { Thread.sleep(2 * 1000L); } catch (InterruptedException e) { }

            // ひとつだけ、アクセス
            System.out.println(smallCache.get("key3") != null);

            try { Thread.sleep(2 * 1000L); } catch (InterruptedException e) { }

            // アクセスしたエントリのみ、キャッシュに残ったまま
            System.out.println(smallCache.get("key3") != null);
            System.out.println(smallCache.get("key4") == null);

            try { Thread.sleep(7 * 1000L); } catch (InterruptedException e) { }

            // もうひとつのエントリも、有効期限が切れる
            System.out.println(smallCache.get("key3") == null);
            System.out.println(smallCache.get("key4") == null);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (defaultCache != null) {
                defaultCache.stop();
            }

            if (smallCache != null) {
                smallCache.stop();
            }

            if (manager != null) {
                manager.stop();
            }
        }
    }
}

サンプルコードを書いたり、実際に動かしたりしたのはここまでです。まあ、興味があったのがここまで、とも言いますか…。あとのライブラリは、さらっとドキュメントを見たりした程度です。

Commons Collection

Commons Collection内の1クラスである、LRUMapをキャッシュとして使ってはどう?みたいなのが出てたので、なんとなく…。登録するエントリの最大数の指定ができ、それを越えればLRUアルゴリズムで消されていく実装です。

それ以上のことはないので、それで要件が済むのであれば。

オフィシャルサイト
http://commons.apache.org/proper/commons-collections/

NitroCache

バージョン0.3が2012年5月?に出たみたいで、ドキュメントはほとんどないのに、パフォーマンス比較の資料だけがアップされている不思議なライブラリ。

NitroCache / EHCache / Infinispan / JCS / Cach4jでのパフォーマンス比較
http://sourceforge.net/p/nitrocache/wiki/Performance/

とにかく速いということを売りにしているみたいですが、ここまで情報がないとねぇ…。パッと見た感じ、有効期限の設定とかはできなさそうです。Evictionはできるみたい。キャッシュサイズの指定と、Evictionアルゴリズムの指定以外は、ほとんど機能がなさそうですね。

この後どうなるかも、よくわからないライブラリです。

オフィシャルサイト
http://sourceforge.net/p/nitrocache/wiki/Home/

OSCache

Ehcacheと並んで有名なキャッシュライブラリだったみたいです…が、今は元のオフィシャルサイトはクローズされてjava.netに移ったうえ、そこからライブラリもダウンロードできない状態になっています。

また、ドキュメントもなくなっているので、機能の確認もできません…。ソースだけは、Subversionで確認することができます。が、さすがにここから動かしたり、調べ回ったりする気にはならないので、ここまでですね。

旧オフィシャルサイト(現在はNot Found)
http://www.opensymphony.com/oscache/

現サイト
https://java.net/projects/oscache

cache4j

2006/3/9にリリースされた0.4を最後に、更新が止まっているキャッシュライブラリ。

ディスク等へのEvictやクラスタ対応も、開発予定の機能に入っていたみたいですが…。アイドル時間によるExpire、TTLの設定、エントリの最大サイズ、キャッシュの削除アルゴリズムはLRU、LFU、FIFOなど普通にキャッシュライブラリとして使えそうな機能は持っているみたいです。

ライセンスはBSD。

オフィシャルサイト
http://cache4j.sourceforge.net/

whirlycache

OSCacheと同じような状態にある、キャッシュライブラリです。高速であることを売りにしていたみたいですが、ドキュメントなども全然ないので、どういうライブラリだったかがわかりません。

https://code.google.com/p/whirlycache/
https://java.net/projects/whirlycache

kitty-cache

2011年12月に1.2がリリースされていますが、その後が??

ソースも見れない感じなので、これも詳細不明なライブラリですね。Ehcacheより、速いとは謳っています…。

オフィシャルサイト
http://code.google.com/p/kitty-cache/

ShiftOne

キャッシュの有効期限の指定、Evictionアルゴリズムの指定、クラスタリングやJMXなど、割と高機能なキャッシュライブラリ。他のライブラリをShiftOneのインターフェースで扱う、アダプタなんて機能もあったみたいです。

2004/2に2.0のBetaが出て、そこで止まっていますね。

オフィシャルサイト
http://jocache.sourceforge.net/

SwarmCache

こちらも、ShiftOneのような高機能なキャッシュライブラリ。この辺りの時期は、キャッシュライブラリでクラスタリングをしようという試みが流行っていたんでしょうか??

2003年10月に1.0のRC2が出て、それ以降更新されていません。

オフィシャルサイト
http://swarmcache.sourceforge.net/


だいぶ長くなりましたが、こんなところで。そのうち、In Memory Data Gridで同じようなこと書きたいですね。