package imoocCache;
import imoocCache.computable.Computable;
import imoocCache.computable.ExpensiveFunction;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
/**
* ImoocCache2缺点:如果在计算完成前,另一个要求计算相同值的请求到来,会导致计算两遍,这和缓存想避免多次计算的初衷恰恰相反
* 改进:利用Future避免重复计算
*/
public class ImoocCache3<A,V> implements Computable<A,V> {
private final Map<A, Future<V>> cache = new ConcurrentHashMap<>();
private final Computable<A,V> c;
public ImoocCache3(Computable<A, V> c) {
this.c = c;
}
@Override
public V compute(A arg) throws Exception {
Future<V> f = cache.get(arg);
if (f == null) {
Callable<V> callable = new Callable<V>() {
@Override
public V call() throws Exception {
return c.compute(arg);
}
};
FutureTask<V> ft = new FutureTask<>(callable);
f = ft;
// 任务开始计算之前先存入缓存,这样其他计算相同任务的线程就可以直接从缓存中读取该任务的执行结果
// 如果该任务还没执行完成,则其他线程调用Future.get方法时会被阻塞
cache.put(arg, ft);
System.out.println("从FutureTask调用了计算函数");
ft.run();
}
return f.get(); // get方法在任务计算过程中会被阻塞,直到任务完成
}
public static void main(String[] args) throws Exception {
ImoocCache3<String, Integer> expensiveComputer = new ImoocCache3<>(
new ExpensiveFunction());
new Thread(() -> {
try {
Integer result = expensiveComputer.compute("666");
System.out.println("第一次的计算结果:"+result);
} catch (Exception e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
try {
Integer result = expensiveComputer.compute("666");
System.out.println("第三次的计算结果:"+result);
} catch (Exception e) {
e.printStackTrace();
}
}).start();
new Thread(()-> {
try {
Integer result = expensiveComputer.compute("667");
System.out.println("第二次的计算结果:"+result);
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
}