キャッシュのように使えるハッシュマップを作りたいのですが。キャッシュには初期サイズがあります。キャッシュがいっぱいになったときにアイテムを挿入しようとすると、最後に使用したアイテムを置き換える必要があります...何かアイデアはありますか?
6 に答える
removeEldestを実装することにより、LinkedHashMapを使用できます。
public static <K,V> Map<K,V> lruCache(final int maxSize) {
return new LinkedHashMap<K,V>(maxSize*4/3, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
return size() > maxSize;
}
};
}
詳細については
http://vanillajava.blogspot.co.uk/2011/06/java-secret-lru-cache-in-java.html
http://blog.meschberger.ch/2008/10/linkedhashmaps-hidden-features.html
グアバを見たことがありますか?キャッシュなどを使用してコレクションを作成するためのファクトリベースのメソッドがあります。
例(リンクされた記事から)
LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
.maximumSize(1000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.removalListener(MY_LISTENER)
.build(
new CacheLoader<Key, Graph>() {
public Graph load(Key key) throws AnyException {
return createExpensiveGraph(key);
}
});
Androidでは、http://developer.android.com/reference/android/util/LruCache.htmlを使用できます。その実装をAOSPから取得し、Apacheライセンスの下で使用できると確信しています。
最も簡単なアプローチはLinkedHashMap
、メソッドを拡張し、オーバーライドしてremoveEldestEntry(Map.Entry<K,V> eldest)
、キャッシュが「フル」であるかどうかを実装で決定することです。
ApacheCommonsのLRUMapを見てください。
最大サイズが固定されたMap実装。エントリがいっぱいになったときにエントリが追加された場合、最も最近使用されていないエントリが削除されます。
最も最近使用されていないアルゴリズムは、getおよびput操作でのみ機能します。反復による値の設定を含む、あらゆる種類の反復は、順序を変更しません。containsKeyやcontainsValueなどのクエリや、ビューを介したアクセスも順序を変更しません。
マップはOrderedMapを実装し、エントリは双方向のOrderedMapIteratorを使用して照会できます。返された順序は、最近使用されたものから最近使用されたものまでです。マップビューのイテレータは、必要に応じてOrderedIteratorにキャストすることもできます。
ResettableIteratorにキャストしてreset()を呼び出すことにより、使用可能なすべてのイテレータを最初にリセットできます。
LRUMapは同期されておらず、スレッドセーフではないことに注意してください。複数のスレッドからこのマップを同時に使用する場合は、適切な同期を使用する必要があります。最も簡単なアプローチは、Collections.synchronizedMap(Map)を使用してこのマップをラップすることです。このクラスは、並行スレッドによってアクセスされるとNullPointerExceptionをスローする可能性があります。
バインドされたキューをハッシュマップと一緒に保持できます。そうすれば、どのアイテムが最も古いかを簡単に知ることができます。