0

つまり、このキャッシュはスレッドセーフであり、LRU プロパティがあります。 CacheBuilder Guava Docsを参照してください。

私の仮定は、同じキーを持つ複数のスレッドが同時に起動された場合です。これには CyclicBarrier が使用され、1 つのスレッドが put() をキャッシュに入れ、他のスレッドは待機します。その後、残りのスレッドは、値がすでにキャッシュにあり、 put() がキャッシュにないことを確認します。

これは、各スレッドが新しい Object() を作成してキャッシュに入れるため、以下のコードには当てはまりません。テストを実行してコンソールを確認し、毎回異なるオブジェクトが作成されることを確認します。


  • CacheBuilderの使用方法に本質的に問題はありますか?
  • 私が使用できるより良い方法はありますか?
  • 使用できるライブラリはありますか?

よろしくお願いします!

import java.util.concurrent.CyclicBarrier;

import org.junit.Test;

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

public class GuavaLRUCacheTest {
    private Cache<String, Object> concurrentLRUCache = CacheBuilder.newBuilder().maximumSize(100).concurrencyLevel(1).build();

    @Test
    public void test() throws Exception {
        // The gate size is set based on the (number of threads to run) + (1 for the current thread).
        CyclicBarrier gate = new CyclicBarrier(4);

        // Same key is used for all threads
        ConcurrentLRUTestThread t1 = new ConcurrentLRUTestThread(gate, "key1");
        ConcurrentLRUTestThread t2 = new ConcurrentLRUTestThread(gate, "key1");
        ConcurrentLRUTestThread t3 = new ConcurrentLRUTestThread(gate, "key1");

        t1.start();
        t2.start();
        t3.start();

        // Open the gate on all threads.
        gate.await();

        t1.join();
        t2.join();
        t3.join();
    }

    class ConcurrentLRUTestThread extends Thread {
        private CyclicBarrier gate;
        private String key;
        public ConcurrentLRUTestThread(CyclicBarrier gate, String key) {
            this.gate = gate;
            this.key = key;
        }
        @Override
        public void run() {
            try {
                gate.await();
                if (concurrentLRUCache.getIfPresent(key) == null) {
                    System.out.println(">>>>> "+ System.nanoTime() +" - "+Thread.currentThread().getId() + " before put " + concurrentLRUCache.getIfPresent(key));
                    concurrentLRUCache.put(key, new Object());
                    System.out.println(">>>>> "+ System.nanoTime() +" - "+Thread.currentThread().getId() + " after put " + concurrentLRUCache.getIfPresent(key));
                } else{
                    System.out.println(">>>>> "+ System.nanoTime() +" - "+Thread.currentThread().getId() + " else " + concurrentLRUCache.getIfPresent(key));
                }  
            } catch (Throwable x) {
                System.out.println(">>>>> "+ System.currentTimeMillis() +" - "+Thread.currentThread().getId() + " ConcurrentLRUTestThread exception");
            }
        }
    }
}
4

1 に答える 1

2

あなたは最初に電話cache.getIfPresentをかけてから、電話をかけようとしますcache.put。これは単一のアトミック アクションとして実行されていないため、機能しません。複数のスレッドがキャッシュに値がないことを確認でき、その結果、複数のcache.put呼び出しが発生します。これを修正する簡単な方法は、チェックとアクションを含むクリティカル セクションを作成することです。その場合、1 つのスレッドだけがキャッシュに値がないことを認識します。幸いなことCacheに、次のことを行うメソッドがすでに含まれていますCache.get(key, valueLoader)。それを使用して値を取得するだけです:


    public class GuavaLRUCacheTest {

    private Cache concurrentLRUCache = CacheBuilder.newBuilder().maximumSize(100).concurrencyLevel(1).build();

    @Test
    public void test() throws Exception {
        // The gate size is set based on the (number of threads to run) + (1 for the current thread).
        CyclicBarrier gate = new CyclicBarrier(4);

        // Same key is used for all threads
        ConcurrentLRUTestThread t1 = new ConcurrentLRUTestThread(gate, "key1");
        ConcurrentLRUTestThread t2 = new ConcurrentLRUTestThread(gate, "key1");
        ConcurrentLRUTestThread t3 = new ConcurrentLRUTestThread(gate, "key1");

        t1.start();
        t2.start();
        t3.start();

        // Open the gate on all threads.
        gate.await();

        t1.join();
        t2.join();
        t3.join();
    }

    class ConcurrentLRUTestThread extends Thread {
        private CyclicBarrier gate;
        private String key;
        public ConcurrentLRUTestThread(CyclicBarrier gate, String key) {
            this.gate = gate;
            this.key = key;
        }
        @Override
        public void run() {
            try {
                gate.await();
                concurrentLRUCache.get(key, Object::new);
            } catch (Throwable x) {
                System.out.println(">>>>> "+ System.currentTimeMillis() +" - "+Thread.currentThread().getId() + " ConcurrentLRUTestThread exception");
            }
        }
    }
}
于 2016-08-12T08:31:15.557 に答える