also verwende CacheBuilder von Guava als ConcurrentLRUCache, was bedeutet, dass dieser Cache threadsicher ist und LRU-Eigenschaften hat, siehe CacheBuilder Guava Docs.Wie verwende ich CacheBuiler von Guava als ConcurrentLRUCache
Meine Annahme ist, wenn mehrere Threads gleichzeitig mit dem gleichen Schlüssel gestartet werden, ein CyclicBarrier wird dafür verwendet, dann wird ein Thread put() in den Cache, während die anderen warten. Danach sehen die verbleibenden Threads, dass ein Wert bereits im Cache ist und nicht put() in den Cache.
Dies gilt nicht für den folgenden Code, da jeder Thread ein neues Object() erstellt und in den Cache legt. Überprüfen Sie, indem Sie den Test ausführen und auf die Konsole schauen, um zu sehen, dass jedes Mal verschiedene Objekte erstellt werden.
- Gibt es etwas von Natur aus falsch mit der Art, wie ich den
CacheBuilder bin mit? - Gibt es bessere Methoden, die ich verwenden kann?
- Gibt es eine Bibliothek, die ich benutzen kann?
Bitte und danke!
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");
}
}
}
}
Verwenden Sie 'LoadingCache', oder zumindest' get (key, callable) '. Wenn Sie auf JDK8 sind, könnten Sie meinen [rewrite] (https://github.com/ben-manes/caffeine) betrachten. –
Sie haben keine Synchronisation zwischen 'getIfPresent' und' put', so dass alle Threads leicht in den ersten 'if'-Zweig gelangen können, während keiner von ihnen' put' aufgerufen hat und dann jeder von ihnen 'put' ausführt. – user3707125