Java Concurrency in Practice(106ページ)で、「Memoizer3
は、複合アクション(put-if-absent)がバッキングマップで実行できないため、問題[2つのスレッドがnullを参照して高価な計算を開始する]ロックを使用してアトミックにする必要があります。私はロックを使ってアトミックにすることができないと言う理由を理解していません。元のコードは次のとおりです。Java Concurrency In Practicesリスティング5.18をロックで原子的に実行できないのはなぜですか?
package net.jcip.examples;
import java.util.*;
import java.util.concurrent.*;
/**
* Memoizer3
* <p/>
* Memoizing wrapper using FutureTask
*
* @author Brian Goetz and Tim Peierls
*/
public class Memoizer3 <A, V> implements Computable<A, V> {
private final Map<A, Future<V>> cache
= new ConcurrentHashMap<A, Future<V>>();
private final Computable<A, V> c;
public Memoizer3(Computable<A, V> c) {
this.c = c;
}
public V compute(final A arg) throws InterruptedException {
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 = ft;
cache.put(arg, ft);
ft.run(); // call to c.compute happens here
}
try {
return f.get();
} catch (ExecutionException e) {
throw LaunderThrowable.launderThrowable(e.getCause());
}
}
}
なぜこの作品のようなものはありませんか?当然の
...
public V compute(final A arg) throws InterruptedException {
Future<V> f = null;
FutureTask<V> ft = null;
synchronized(this){
f = cache.get(arg);
if (f == null) {
Callable<V> eval = new Callable<V>() {
public V call() throws InterruptedException {
return c.compute(arg);
}
};
ft = new FutureTask<V>(eval);
f = ft;
cache.put(arg, ft);
}
}
if (f==ft) ft.run(); // call to c.compute happens here
...
ええ、著者はテキストにputIfAbsentソリューションを提供しています。 – PeteyPabPro