多线程缓存优化思想

1.背景
题库 随机生成N张试卷,每张试卷M个题目,每个题目要到 数据库 下载 相应的图片,
而且在N张试卷 的 N*M 个题目中 会存在很多 相同的题目。这就给我们可以设置缓存
大大优化处理速度。

2.多线程优化 N张试卷思想

//生成文档的线程池
private static ExecutorService docMakeService
= Executors.newFixedThreadPool(Consts.THREAD_COUNT_BASE*2);

private static CompletionService docCompletionService
= new ExecutorCompletionService(docMakeService);


//生成文档的线程
private static class MakeDocTask implements Callable<String>{
private PendingDocVo pendingDocVo;

public MakeDocTask(PendingDocVo pendingDocVo) {
this.pendingDocVo = pendingDocVo;
}

@Override
public String call() throws Exception {
long start = System.currentTimeMillis();
String localName = DocService.makeAsyn(pendingDocVo);
System.out.println("文档"+localName+"生成耗时:"
+(System.currentTimeMillis()-start)+"ms");
return localName;
}
}


main
for(PendingDocVo doc:docList){
docCompletionService.submit(new MakeDocTask(doc));
}

for(PendingDocVo doc:docList){
Future<String> futureLocalName = docCompletionService.take();
uploadCompletionService.submit(new UploadDocTask(futureLocalName.get()));
}


3.多线程 缓存 优化生成题目 核心思想
1)
//存放处理过题目内容的缓存
private static ConcurrentHashMap<Integer,ProblemCacheVo> problemCache
= new ConcurrentHashMap<Integer,ProblemCacheVo>();
2)
//存放正在处理的题目的缓存,防止多个线程同时处理一个题目
private static ConcurrentHashMap<Integer,Future<ProblemCacheVo>>
processingProblemCache = new ConcurrentHashMap<Integer,Future<ProblemCacheVo>>();

3)
//处理的题目的线程池
private static ExecutorService makeProblemExec =
Executors.newFixedThreadPool(Consts.THREAD_COUNT_BASE*2);

4)
//供调用者使用,返回题目的内容或者任务
public static MultiProblemVo makeProblem(Integer problemId){
//检查缓存中是否存在
ProblemCacheVo problemCacheVo = problemCache.get(problemId);
if(null==problemCacheVo){
//System.out.println("题目【"+problemId+"】在缓存中不存在,需要新启任务");
return new MultiProblemVo(getProblemFuture(problemId));
}else{
//拿摘要,一篇文档中的所有题目的摘要其实可以一次性取得,以减少对数据库的访问
String problemSha = ProblemBank.getProblemSha(problemId);
if(problemCacheVo.getProblemSha().equals(problemSha)){
//System.out.println("题目【"+problemId+"】在缓存中存在且没有修改过,可以直接使用。");
return new MultiProblemVo(problemCacheVo.getProcessedContent());
}
else{
//System.out.println("题目【"+problemId+"】的摘要发生了变化,启动任务更新缓存。");
return new MultiProblemVo(getProblemFuture(problemId));
}
}

}

5)
//返回题目的工作任务
private static Future<ProblemCacheVo> getProblemFuture(Integer problemid){
Future<ProblemCacheVo> problemFuture = processingProblemCache.get(problemid);
if (problemFuture==null){
ProblemDBVo problemDBVo = ProblemBank.getProblem(problemid);
ProblemTask problemTask = new ProblemTask(problemDBVo,problemid);
//当前线程新启了一个任务
FutureTask<ProblemCacheVo> ft =
new FutureTask<ProblemCacheVo>(problemTask);
problemFuture = processingProblemCache.putIfAbsent(problemid,ft);
if (problemFuture==null){
//表示没有别的线程正在处理当前题目
problemFuture = ft;
makeProblemExec.execute(ft);
//System.out.println("题目【"+problemid+"】计算任务启动,请等待完成>>>>>>>>>>>>>。");
}else{
System.out.println("刚刚有其他线程启动了题目【"+problemid+"】的计算任务,任务不必开启");
}
}else{
//System.out.println("当前已经有了题目【"+problemid+"】的计算任务,不必重新开启");
}
return problemFuture;
}

6)
//处理题目的任务
private static class ProblemTask implements Callable<ProblemCacheVo>{

private ProblemDBVo problemDBVo;
private Integer problemId;

public ProblemTask(ProblemDBVo problemDBVo, Integer problemId) {
this.problemDBVo = problemDBVo;
this.problemId = problemId;
}

@Override
public ProblemCacheVo call() throws Exception {
try {
ProblemCacheVo problemCacheVo = new ProblemCacheVo();
problemCacheVo.setProcessedContent(
BaseProblemService.makeProblem(problemId,problemDBVo.getContent()));
problemCacheVo.setProblemSha(problemDBVo.getSha());
problemCache.put(problemId,problemCacheVo);
return problemCacheVo;
} finally {
//无论正常还是异常,都需要将生成的题目的任务从缓存移除
processingProblemCache.remove(problemId);
}
}
}

}


4.核心思想总结
1)存放处理过题目内容的缓存:
如果缓存中存在,就不需要处理,直接返回 题目内容结果;
return new MultiProblemVo(problemCacheVo.getProcessedContent());
缓存不存在,则要开启一个 处理题目的线程。进入3)
return new MultiProblemVo(getProblemFuture(problemId));

2)存放正在处理的题目内容缓存
//存放正在处理的题目的缓存,防止多个线程同时处理一个题目
private static ConcurrentHashMap<Integer,Future<ProblemCacheVo>>
processingProblemCache = new ConcurrentHashMap<Integer,Future<ProblemCacheVo>>();

//处理的题目的线程池
private static ExecutorService makeProblemExec =
Executors.newFixedThreadPool(Consts.THREAD_COUNT_BASE*2);


3)返回题目的工作任务
首先看看 //存放正在处理的题目的缓存,防止多个线程同时处理一个题目 正在出路题目的缓存中有没有
如果有 说明任务已经开启,不需要再重新开启
如果没有,重新创建一个线程任务 然后利用 problemFuture = processingProblemCache.putIfAbsent(problemid,ft);
看看此刻 处理线程任务缓存中有没有任务,
如果problemFuture==null ,表明没有任务正在处理,启动线程 makeProblemExec.execute(ft);
如果有值,说明在刚刚的片刻已经有任务再启动 不需重新启动


5.问题
1)正在内存中处理的任务 是什么时候投放到 缓存的?
在内存中正在处理任务的缓存中判断没有任务,然后创建一个任务 ,然后利用 putIfAbsent 投放到 在内存中处理任务缓存中。注意处理完了 就要移除

2)任务结果是什么时候投放到 题目处理结果缓存的?
在任务处理的线程里,处理完了 就投放到缓存,且还要正在内存中 处理的缓存中移除
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值