文章目录
- 引言
- 基于缓存存储运算结果
- 锁分段散列减小锁粒度
- 异步化提升处理效率
- 原子化避免重复运算
- 小结
- 参考
引言
基于缓存存储运算结果
利用缓存避免非必要的计算,提升结果获取速度,但还是存在问题,每个线程都需要等待锁才能看结果和运算:
public final Map<Integer, Integer> cache = new HashMap<>();
public synchronized int compute(int arg) {
if (cache.containsKey(arg)) {//若存在直接返回结果
return cache.get(arg);
} else {//若不存在则计算并返回
int result = doCompute(arg);
cache.put(arg, result);
return result;
}
}
private int doCompute(int key) {
ThreadUtil.sleep(500);
return key << 1;
}
锁分段散列减小锁粒度
利用分段锁分散压力,但是运算耗时可能导致重复计算和put操作:
public final Map<Integer, Integer> cache = new ConcurrentHashMap<>();
public int compute(int arg) {
Integer res = cache.get(arg);
if (res == null) {
int result = doCpmpute(arg);
cache.put(arg, result);
}
return res;
}
private int doCpmpute(int arg) {
ThreadUtil.sleep(3000);
return arg << 1;
}
异步化提升处理效率
使用future避免计算的阻塞,当然因为判空和创建任务非原子操作,很可能还是出现重复计算的情况:
public final Map<Integer, FutureTask<Integer>> cache = new ConcurrentHashMap<>();
public int compute(int key) throws ExecutionException, InterruptedException {
FutureTask<Integer> f = cache.get(key);
if (f == null) {
FutureTask<Integer> futureTask = new FutureTask<>(() -> doCompute(key));
//缓存保证下一个线程看到时直接取出使用
cache.put(key, futureTask);
futureTask.run();
f=futureTask ;
}
return f.get();
}
private int doCompute(int arg) {
ThreadUtil.sleep(3000);
return arg << 1;
}
原子化避免重复运算
原子操作避免重复计算,并发运算一个数字时都采用同一个任务的结果
public int compute(int key) throws ExecutionException, InterruptedException {
FutureTask<Integer> f = cache.get(key);
if (f == null) {
FutureTask<Integer> futureTask = new FutureTask<>(() -> doCompute(key));
//原子操作添加,若返回空说明第一次添加,则让这个任务启动,其他线程直接基于缓存中的任务获取结果
f = cache.putIfAbsent(key, futureTask);
if (f == null) {
f = futureTask;
f.run();
}
futureTask.run();
f = futureTask;
}
return f.get();
}