1

序章

ArrayDequeと次の Genericsソリューションを使用して、LRUポリシーを使用して単純なキャッシュを実装しました。

public class Cache<T> extends ArrayDeque<T> implements Serializable {
    private static final long serialVersionUID = 1L;
    private int MAX_SIZE;

    public Cache(int maxSize) {
        MAX_SIZE = maxSize;
    }

    public void store(T e) {
        if (super.size() >= MAX_SIZE) {                 
            this.pollLast();
        }
        this.addFirst(e);       
    }

    public T fetch(T e) {
        Iterator<T> it = this.iterator();
        while (it.hasNext()) {
            T current = it.next();
            if (current.equals(e)) {
                this.remove(current);
                this.addFirst(current);
                return current;
            }
        }
        return null;
    }

}

問題

クラスをインスタンス化して要素をプッシュすると、

Cache<CachedClass> cache = new Cache<CachedClass>(10);
cache.store(new CachedClass());

この時点では、キューには何も含まれていません。

なぜこうなった?


観察

ちなみに、CachedClassオーバーライドはメソッドをオーバーライドします.equals()


テスト

 public class CacheTest {

    @Test
    public void testStore() {
        Cache<Integer> cache = new Cache<Integer>(3);

        cache.store(1);
        assertTrue(cache.contains(1));

        cache.store(2);
        cache.store(3);
        cache.store(4);

        assertEquals(cache.size(), 3);      
    }

    @Test
    public void testFetch() {
        Cache<Context> cache = new Cache<Context>(2);

        Context c1 = new Context(1);
        Context c2 = new Context(2);

        cache.store(c1);
        cache.store(c2);                

        assertEquals((Context) cache.peekFirst(), (new Context(2)));

        Context c = cache.fetch(c1);

        assertTrue(c == c1);        
        assertEquals(cache.size(), 2);
        assertEquals((Context) cache.peekFirst(), (new Context(1)));

    }

 }

編集両方のテストに合格しました。

最初のテストに合格します。を投げることに失敗しAssertExceptionます

assertTrue(cache.peekFirst() == 1);

2番目のテストの

4

3 に答える 3

1

LinkedHashMap の Javadoc は言う

「この種のマップは、LRU キャッシュの構築に適しています。」

これを無視するには、本当に正当な理由が必要です。私の推測では、パフォーマンスは put の実装と Map を使用した get の実装の間で区別がつかず、はるかに優れていると思いますが、独自のベンチマークを実行してみませんか。

最後に、実装 (および LinkedHashMap によって提供されるもの) はスレッドセーフではありません。これが問題になる場合は、同期ロジックによってパフォーマンス オーバーヘッドが追加されます。

于 2012-11-05T17:23:59.033 に答える
0

私はこれをメインメソッドで行います:

    Cache<Integer> cache = new Cache<Integer>(10);
    cache.store(new Integer(0)); 
    System.out.println(cache.size()); // prints 1
    Integer foo = cache.fetch(new Integer(0));
    System.out.println(foo == null); // prints false

1 が出力されるため、 には 1 つの要素がありますCache。正常に動作します。

CachedClassあなたのmuss overrideを取得するためequals()。あなたのコードは、変更しなくても意図したとおりに完全に機能します。

于 2012-11-05T14:51:22.907 に答える
0

LinkedHashMap を LRU キャッシュとして使用します。

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

重要な違いは、キーが値に関連付けられていることです。キャッシュをセットとして実装する場合、できることは、既に持っているオブジェクトがキャッシュにあるかどうかを確認することだけです。これは、私見としてはあまり役に立ちません。

テスト

@Test
public void testStore() {
    Map<Integer, String> cache = lruCache(3);
    cache.put(1, "one");
    assertEquals("one", cache.get(1));

    cache.put(2, "two");
    cache.put(3, "three");
    cache.put(4, "four");

    assertEquals(cache.size(), 3);
    assertEquals(null, cache.get(1));
}

@Test
public void testFetch() {
    Map<Integer, String> cache = lruCache(3);

    cache.put(1, "one");
    cache.put(2, "two");

    assertEquals((Integer) 1, cache.keySet().iterator().next());

    String s = cache.get(1);

    assertEquals("one", s);
    assertEquals(cache.size(), 2);
    assertEquals((Integer) 2, cache.keySet().iterator().next());
}
于 2012-11-05T15:27:19.583 に答える