次の簡単なプログラムを考えてみましょう:
import java.util.concurrent.ExecutionException;
import java.util.logging.Logger;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
public class Main {
final static Logger logger = Logger.getLogger(Main.class.getName());
public static void main(String[] args) throws ExecutionException, InterruptedException {
final LoadingCache<Integer, String> cache = CacheBuilder.newBuilder().build(
new CacheLoader<Integer, String>() {
@Override
public String load(Integer arg0) throws Exception {
logger.info("Cache builder START: " + arg0);
Thread.sleep(4000);
logger.info("Cache builder FINISH: " + arg0);
return "This is what CacheBuilder returned for key " + arg0;
}
});
Thread getterThread = new Getter(cache);
getterThread.start();
Thread setterThread = new Setter(cache);
setterThread.start();
getterThread.join();
setterThread.join();
logger.info("Finally in cache we have: " + cache.get(1));
}
private static final class Getter extends Thread {
private final LoadingCache<Integer, String> cache;
private Getter(LoadingCache<Integer, String> cache) {
this.cache = cache;
}
@Override
public void run() {
try {
logger.info("Getter thread reads 1st time " + cache.get(1)
+ " <<<<<<<<<< WHAT !?!");
// allow the setter to put the value
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
logger.info("Getter thread reads 2nd time " + cache.get(1));
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
private static final class Setter extends Thread {
private final LoadingCache<Integer, String> cache;
private Setter(LoadingCache<Integer, String> cache) {
this.cache = cache;
}
@Override
public void run() {
try {
// deliberately wait to allow the Getter thread
// trigger cache loading
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
cache.put(1, "This isn't where I parked my car!");
logger.info("Setter thread now reads: " + cache.get(1));
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}
出力は次のとおりです。
2013-11-08 15:24:32 INFO Main$1 load Cache builder START: 1
2013-11-08 15:24:32 INFO Main$Setter run Setter thread now reads: This isn't where I parked my car!
2013-11-08 15:24:36 INFO Main$1 load Cache builder FINISH: 1
2013-11-08 15:24:36 INFO Main$Getter run Getter thread reads 1st time This is what CacheBuilder returned for key 1 <<<<<<<<<< WHAT !?!
2013-11-08 15:24:37 INFO Main$Getter run Getter thread reads 2nd time This isn't where I parked my car!
2013-11-08 15:24:37 INFO Main main Finally in cache we have: This isn't where I parked my car!
Getterスレッドで「これはキー1に対してCacheBuilderが返したものです」を取得しています。明らかにこれは、Getter によって呼び出された get(1) がキャッシュの読み込みをトリガーするためですが、その間に Setter スレッドが来て、キー 1 に別の値を設定するためです。車を止めた場所じゃない!」(Getter が 1 の値を取得するのは 2 回目です)。
私は何か見落としてますか ?
前もって感謝します