LRUは、キャッシュでよくある方法ですよね。
LinkedHashMapを使って、LRU方式でキャッシュするサンプル
LinkedHashMapにデータをキャッシュします。
また、キャッシュしたデータから取得、データの追加をして、それぞれの時点でキャッシュの中身を確認します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; public class LRUCacheTest<K, V> extends LinkedHashMap<K, V> { private final int maxSize; public LRUCacheTest(int maxSize) { super(maxSize, 0.75f, true); this.maxSize = maxSize; } @Override protected boolean removeEldestEntry(Map.Entry<K, V> eldest) { return size() > maxSize; } public static void main(String[] args) { Map<String, String> cache = Collections.synchronizedMap(new LRUCacheTest<>(3)); cache.put("1", "A"); cache.put("2", "B"); cache.put("3", "C"); System.out.println("[1]:" + cache); String b = cache.get("2"); System.out.println("[2]:" + cache); cache.put("4", "D"); System.out.println("[3]:" + cache); } } |
実行結果
LinkedHashMapにキャッシュした中身を出力されます。
途中で、”2″にアクセスしているので、順序が変わっています。
追加後も、格納している数は変わりませんね。
1 2 3 | [1]:{1=A, 2=B, 3=C} [2]:{1=A, 3=C, 2=B} [3]:{3=C, 2=B, 4=D} |
サンプルの解説
今回は、LinkedHashMapを継承して作っています。
ポイントは、LinkedHashMap#removeEldestEntry(Map.Entry
このメソッドは、putなどのアイテム追加のメソッドから呼び出されます。
この例では、アイテム追加時、上限サイズ(3)を超えた場合、削除するようにtrueを返しています。
また、今回の例では意味を成していませんが、Collections.synchronizedMap(Map)で、スレッドセーフのマップにしています。
ちなみに、LinkedHashMapは、このような特別な理由がなければ、あまり使いません。
名前の通り、HashMapを拡張したものなので、HashMapに比べて少し性能が下がります。
単に連想配列レベルで使用するだけなら、素直にHashMapを使いましょう。