考虑这个简单的程序:
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 线程中得到这个“这是 CacheBuilder 为键 1 返回的内容”。显然,这是因为 Getter 调用的 get(1) 触发了缓存加载,但与此同时,Setter 线程来了并为键 1 放置了一些其他值。我希望它返回与 Setter = "This不是我停车的地方!” (我得到第二次 Getter 检索 1 的值)。
我错过了什么 ?
提前致谢