public class MayFail implements Computable<String, Integer>{
@Override
public Integer compute(String arg) throws Exception {
double random = Math.random();
if (random > 0.5) {
throw new IOException(Thread.currentThread().getName()+" 读取文件出错");
}
Thread.sleep(2000);
System.out.println(arg+“被加入缓存”);
return Integer.valueOf(arg);
}
}
public class ImoocCache9<A, V> implements Computable<A, V> {
private final ConcurrentHashMap<A, Future<V>> cache
= new ConcurrentHashMap<>();
private final Computable<A, V> c;
public ImoocCache9(Computable<A, V> c) {
this.c = c;
}
@Override
public V compute(A arg) throws InterruptedException, ExecutionException {
while (true) {
Future<V> f = cache.get(arg);
if (f == null) {
FutureTask<V> ft = new FutureTask<>(()->c.compute(arg));
f = cache.putIfAbsent(arg, ft);
if (f == null) {
f = ft;
System.out.println(Thread.currentThread().getName()+" 从FutureTask调用了计算函数");
ft.run();
}
}
try {
return f.get();
} catch (CancellationException e) {
System.out.println("被取消了");
cache.remove(arg);
throw e;
} catch (InterruptedException e) {
cache.remove(arg);
throw e;
} catch (ExecutionException e) {
System.out.println(Thread.currentThread().getName()+" "+e.getMessage()+" 计算错误,需要重试");
cache.remove(arg);
}
}
}
public static void main(String[] args) throws Exception {
ImoocCache9<String, Integer> expensiveComputer = new ImoocCache9<>(
new MayFail());
new Thread(new Runnable() {
@Override
public void run() {
try {
Integer result = expensiveComputer.compute("666");
System.out.println("第一次的计算结果:" + result);
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
Integer result = expensiveComputer.compute("666");
System.out.println("第二次的计算结果:" + result);
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
Integer result = expensiveComputer.compute("667");
System.out.println("第三次的计算结果:" + result);
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
}
打印:
Thread-2 从FutureTask调用了计算函数
Thread-1 从FutureTask调用了计算函数
Thread-2 java.io.IOException: Thread-2 读取文件出错 计算错误,需要重试
Thread-1 java.io.IOException: Thread-1 读取文件出错 计算错误,需要重试
Thread-0 java.io.IOException: Thread-1 读取文件出错 计算错误,需要重试
Thread-1 从FutureTask调用了计算函数
Thread-2 从FutureTask调用了计算函数
Thread-1 java.io.IOException: Thread-1 读取文件出错 计算错误,需要重试
Thread-0 从FutureTask调用了计算函数
Thread-1 从FutureTask调用了计算函数
Thread-2 java.io.IOException: Thread-2 读取文件出错 计算错误,需要重试
Thread-1 java.io.IOException: Thread-1 读取文件出错 计算错误,需要重试
Thread-0 java.io.IOException: Thread-0 读取文件出错 计算错误,需要重试
Thread-1 从FutureTask调用了计算函数
Thread-2 从FutureTask调用了计算函数
Thread-1 java.io.IOException: Thread-1 读取文件出错 计算错误,需要重试
Thread-0 从FutureTask调用了计算函数
Thread-1 从FutureTask调用了计算函数
Thread-2 java.io.IOException: Thread-2 读取文件出错 计算错误,需要重试
Thread-1 java.io.IOException: Thread-1 读取文件出错 计算错误,需要重试
Thread-0 java.io.IOException: Thread-0 读取文件出错 计算错误,需要重试
Thread-1 从FutureTask调用了计算函数
Thread-2 从FutureTask调用了计算函数
Thread-1 java.io.IOException: Thread-1 读取文件出错 计算错误,需要重试
Thread-0 从FutureTask调用了计算函数
Thread-1 从FutureTask调用了计算函数
Thread-0 java.io.IOException: Thread-0 读取文件出错 计算错误,需要重试
Thread-0 从FutureTask调用了计算函数
//重试导致缓存重复添加****************************************
667被加入缓存
666被加入缓存
666被加入缓存
第一次的计算结果:666
第三次的计算结果:667
第二次的计算结果:666
Process finished with exit code 0
老师,看打印结果,重试有时候会导致缓存重复添加,您的代码也是,运行多次也会出现这个问题,没想明白咋回事?