业务场景
现有一个消耗资源比较大的计算业务需要优化,如果是同一个计算业务,需要保证只被计算一次,后面再有此计算,则直接从缓存中读取结果
用例图
流程图
类图
具体代码实现
接口
这里主要涉及的两个接口:
- 计算接口:执行的计算逻辑
- 缓存接口:执行的是缓存相关操作
计算接口
public interface Computer {
Integer compute(String id);
}
缓存接口
public interface Cache {
Integer query(String key);
void save(String key, FutureTask<Integer> value);
}
具体业务代码
实际计算类
public class ActualComputer implements Computer {
@Override
public Integer compute(String id) {
System.out.println("用户ID"+id+"正在计算");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return id.hashCode();
}
}
ConcurrentHashMap实现的缓存类
public class HashMapCache implements Cache {
private final static ConcurrentHashMap<String,Future<Integer>> cache = new ConcurrentHashMap<>();
@Override
public Integer query(String key) {
try {
Future<Integer> integerFuture = cache.get(key);
if(integerFuture == null){
return null;
}
return integerFuture.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
return null;
}
@Override
public void save(String key, FutureTask<Integer> value) {
Future<Integer> integerFuture = cache.putIfAbsent(key, value);
// 如果有值了 则不再计算 防止重复计算
if(integerFuture == null){
value.run();
}
// 非原子操作,最终还是会重复计算
// cache.put(key,value);
// value.run();
}
}
使用装饰器模式实现的计算装饰类
public class DecorateComputer implements Computer{
private Cache cache;
private Computer computer;
public DecorateComputer(Cache cache, Computer computer) {
this.cache = cache;
this.computer = computer;
}
@Override
public Integer compute(String id) {
Integer result = cache.query(id);
if(result == null){
// 计算耗时的任务需要后置 防止线程重复执行计算 此时需要使用futureTask
FutureTask<Integer> futureTask = new FutureTask<>(()->computer.compute(id));
cache.save(id,futureTask);
result = cache.query(id);
}
System.out.println("用户ID"+id+"计算结果:"+result);
return result;
}
}
入口主程序
public class Main {
public static void main(String[] args) {
ActualComputer actualComputer = new ActualComputer();
HashMapCache hashMapCache = new HashMapCache();
DecorateComputer decorateComputer = new DecorateComputer(hashMapCache, actualComputer);
new Thread(()->decorateComputer.compute("jack")).start();
new Thread(()->decorateComputer.compute("susan")).start();
new Thread(()->decorateComputer.compute("jack")).start();
}
}