Brian Goetz的Java Concurrency In Practice提供了一个用于并发使用的高效可伸缩缓存的示例。示例的最终版本显示了类Memoizer (pg 108)的实现,其中显示了这样一个缓存。我想知道为什么这个类没有用@ThreadSafe注解?缓存的客户端,class Factorizer,使用@ThreadSafe进行了正确的注释。附录指出,如果一个类没有使用@ThreadSafe或@Immutable进行注释,那么就应该假定它不是线程安全的。不过,Memoizer似乎是线程安全的。
以下是Memoizer的代码:
public class Memoizer<A, V> implements Computable<A, V> {
private final ConcurrentMap<A, Future<V>> cache
= new ConcurrentHashMap<A, Future<V>>();
private final Computable<A, V> c;
public Memoizer(Computable<A, V> c) { this.c = c; }
public V compute(final A arg) throws InterruptedException {
while (true) {
Future<V> f = cache.get(arg);
if (f == null) {
Callable<V> eval = new Callable<V>() {
public V call() throws InterruptedException {
return c.compute(arg);
}
};
FutureTask<V> ft = new FutureTask<V>(eval);
f = cache.putIfAbsent(arg, ft);
if (f == null) { f = ft; ft.run(); }
}
try {
return f.get();
} catch (CancellationException e) {
cache.remove(arg, f);
} catch (ExecutionException e) {
throw launderThrowable(e.getCause());
}
}
}}
发布于 2010-12-30 09:54:22
它看起来当然是线程安全的。如果我没记错的话,在这个特定版本的Memoizer中,Goetz展示了如何使用cache.putIfAbsent来避免缓存的get和put方法之间的竞争条件。
正如其他人指出的那样,它可能被遗漏了,你必须依靠书中的注释来判断这是不是“好”的版本。
发布于 2010-12-25 09:47:48
我想去问问Goetz吧。这可能只是一个疏忽。
然而,这些注释的问题是它们没有意义。理想情况下,它们需要与FindBugs等自动错误查找程序结合使用,在这种情况下,注释@Immutable (例如)将允许FindBugs打开其字段突变检测器。
没有这样的检查,库的作者很容易将@ThreadSafe或@Immutable附加到一个类,即使它不是真的!我不是在暗示故意欺骗,而是诚实的错误...然而,结果是库的使用者不能依赖注解,那么有什么意义呢?
https://stackoverflow.com/questions/4528382
复制相似问题