- 浏览: 67814 次
文章分类
最新评论
-
小色帝:
我是天才是打发
Jquery实现的Tabs页 -
小色帝:
小色帝 写道1111而温热
Jquery实现的Tabs页 -
小色帝:
1111而温热
Jquery实现的Tabs页
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)任务结果是什么时候投放到 题目处理结果缓存的?
在任务处理的线程里,处理完了 就投放到缓存,且还要正在内存中 处理的缓存中移除
题库 随机生成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)任务结果是什么时候投放到 题目处理结果缓存的?
在任务处理的线程里,处理完了 就投放到缓存,且还要正在内存中 处理的缓存中移除
发表评论
-
c3p0代码动态切换数据源
2018-08-06 17:54 1074public class PARPDatasource imp ... -
sql 优化开多个线程跑
2018-07-11 09:54 678select /*+ parallel(8) */ * fr ... -
redis 事物限制频率和获得令牌
2018-07-11 02:50 925package com.dongnaoedu.tony.ser ... -
Redis分布式锁解决抢购问题
2018-07-11 02:39 1326废话不多说,首先分享一个业务场景-抢购。一个典型的高并发问题, ... -
StringWriter 接收异常信息
2018-07-05 18:42 442try { int a=1/0; } catch (E ... -
RedisCacheServiceUtil
2018-06-29 15:06 379package com.paic.icorepnbs.web. ... -
jedis 操作redis
2018-06-26 09:13 368//连接redis ,redis的默认端口是6379 Je ... -
网络编程之使用HttpClient批量上传文件
2018-05-28 01:12 540网络编程之使用HttpClient批量上传文件(一) 2014 ... -
oracle 正则表达式 替换 ‘’:
2018-05-18 18:04 578select /*+ parallel(8) */ t.na ... -
java web 导出 下拉 excle
2018-05-15 17:03 457@RequestMapping(value = "/ ... -
Java Socket编程
2016-12-28 23:28 337对于Java Socket编程而言,有两个概念,一个是Serv ... -
Java多线程学习(吐血超详细总结)
2016-12-27 17:15 415目录(?)[-] 1.一扩展javalangThread类 2 ... -
JAVA多线程实现的三种方式
2016-12-27 17:16 417Java多线程实现方式主要有三种:继承Thread类、实现Ru ... -
Maven 入门菜鸟教程
2016-12-02 10:02 1174学习maven的使用,看到一篇很实用的入门教程(菜鸟级入门) ... -
Java 读写Properties配置文件
2016-08-22 15:00 401Java 读写Properties配置文件 1.Pro ... -
JAVA前端与后端参数传递方法小结
2016-07-26 10:54 46561,从Action中传值到JSP页面的方法 ①在Actio ... -
苟富贵
2013-02-25 09:43 0额梵蒂冈过v梵蒂冈北方多汇报地方环保 -
Request的getParameter和getAttribute方法的区别
2013-01-22 10:01 647HttpServletRequest.getParameter ... -
Eclipse快捷键小结
2012-12-26 11:26 734Eclipse快捷键小结 Eclipse ... -
JAVA去空格
2012-12-20 16:53 652String ccc=” he l l o , w o r l ...
相关推荐
这就是多线程下载的核心思想,通过创建多个子线程,每个线程负责下载文件的一部分,从而在后台高效地完成下载任务。 1. **线程池和ExecutorService**: Android开发者可以使用Java的`ExecutorService`来管理和调度...
本项目是针对操作系统课程设计的一个多线程Web服务器,它利用C语言实现了服务器的基本功能,并且引入了线程池的设计思想,以优化性能和资源管理。下面我们将深入探讨这个项目中的关键知识点。 1. **多线程技术**:...
在操作系统领域,生产者-消费者问题是经典的问题之一,它涉及到多线程同步和资源管理。本项目通过使用多线程同步方法解决这个问题,具体表现为有界缓冲区的管理,其中包含20个存储单元,存储1~20的整型数。下面是...
多线程下载的核心思想是将一个大文件分解为多个小部分,然后启动多个线程(通常比CPU核心数量多)来并行下载这些部分。每个线程独立请求服务器,减少了单一连接的等待时间,提高了整体下载效率。同时,如果某个线程...
- **并发下载**:多线程下载的基本思想是将一个大文件分割成多个小部分,然后同时启动多个线程进行下载。每个线程负责下载一部分文件,这样可以提高下载速度,因为网络连接可以并行处理多个请求。 - **负载均衡**...
然而,在多线程环境下,如何确保LRU缓存的正确性和性能成为了一个挑战。本篇文章将深入探讨一个简单的多线程LRUCache实现及其测试。 一、LRUCache原理 LRUCache的核心思想是:当缓存满时,最近最少使用的数据会被...
综上所述,"线程下载图片,并用LruCache缓存"是一种常见的Android性能优化策略,通过多线程技术提高图片加载速度,同时利用LruCache内存缓存来减少网络请求,提升用户体验。理解并熟练运用这些技术,对于开发高质量...
本文将深入探讨如何利用异步加载和多线程技术优化ListView图片加载,提升用户体验。 1. **主线程与UI更新** - 主线程(UI线程)负责处理用户交互和更新UI。当主线程执行耗时操作,如加载大量图片,会导致应用失去...
【片上多线程处理器调度策略分析】 片上多线程处理器(Chip Multi-Threading,CMT)是一种高性能...本文的研究为理解和优化片上多线程处理器的性能提供了重要的理论基础和实践指导,对相关领域的研究具有参考价值。
- **避免数据竞争**:尽量避免多线程中对同一数据的并发访问,这可能导致频繁的缓存失效和同步开销。 ### 6. 缓存的局限性 虽然高速缓存提高了性能,但也存在一些问题,如缓存污染(不常用的数据占据了缓存空间)...
多线程下载的核心思想是通过同时发起多个HTTP请求,利用服务器的并发处理能力,从而提高下载速度。服务器CPU对每个线程分配相同的时间片,带宽也均匀分配给各个线程,因此,客户端开启的线程越多,能获取的服务器...
虽然实际的数据库缓存系统可能更复杂,但这个例子提供了一个基础的多线程模型。 在`Producer`类中,数据被写入一个本地文件("myvector.obj"),这里可以视为一种简单的内存之外的缓存形式。`ObjectOutputStream`...
它在内部使用`DiskLruCache`进行实际操作,并处理并发控制,保证多线程环境下的安全性。 5. **SizeUtils**:辅助类,用于计算文件的大小,确保缓存不会超出设定的最大大小。 优化与增强: 1. **缓存策略**:可以...
由于ThreadLocal是在当前线程内操作,因此它不需要在多个线程间进行数据同步,从而进一步优化了性能。 本文对这两种缓存方式的实现原理进行了深入研究,并从时间复杂度、实现难度、编程思想、扩展性等多个维度进行...
kfifo的设计保证了在多线程环境下的并发安全性,通过原子操作确保数据一致性。其核心思想是使用两个指针,一个指向待读数据的头部,另一个指向待写数据的尾部,通过调整这两个指针来实现数据的添加和移除。 2. **...
这种数据结构使得在多线程环境下,生产者可以不断地向缓冲区写入数据,而消费者可以同时读取数据,两者互不影响,提高了系统的并行处理能力。 在标题提到的"arrayBuffer(环形缓冲区)"中,我们可以推断这是一个实现...
Java多线程是Java编程中的核心概念,它允许程序同时执行多个任务,提高了系统的效率和响应性。在Java中,线程是程序执行的最小单位,由Java虚拟机(JVM)来管理和调度。理解线程的创建、同步、通信以及生命周期管理...
LRUCache本身是线程安全的,但是进行多个缓存操作时需要同步处理。例如,下面是一个简单的同步代码示例: ```java synchronized (cache) { if (cache.get(key) == null) { cache.put(key, value); } } ``` #### ...
3. **线程安全**:为了适应多线程环境,`Fuse`设计为线程安全,确保在并发访问时不会出现问题。 4. **自定义配置**:开发者可以灵活地调整缓存大小、磁盘路径等参数,以适应不同应用场景的需求。 5. **异常处理**:...
- **任务队列的局限性**:即使使用任务队列对任务进行串行处理,由于服务端可能存在多个工作线程,这些任务仍然可能被并行执行。 - **多服务部署的影响**:即使在单一服务内实现了串行化,但如果该服务是分布式部署...