Java并发编程实践(读书笔记) 任务执行(未完)
任务的定义
大多数并发程序都是围绕任务进行管理的.任务就是抽象和离散的工作单元.
任务的执行策略
1.顺序的执行任务
这种策略的特点是一般只有按顺序处理到来的任务.一次只能处理一个任务,后来其它任务都要等待处理.响应性很糟糕,吞吐量低.系统资源利用率低.
2.显示的为任务创建线程
为每个任务创建对应一个线程,响应快,系统资源利用路高.缺点是资源消耗量大,如果有大量任务要执行的话,系统迟早会因为无限制创建过多的线程而造成内存耗尽.特别当创建的线程数量远远大于系统的CPU核数,由于每一个核同一时刻只能执行一个线程,所以系统要执行很多不必要的线程上下文切换,造成资源大量浪费.
3.Executor框架
Executor接口本身很简单,就一个execute方法.但是由Executor这个接口衍生出来的类,功能非常强大.可以这么认为,Executor框架这是线程管理的工具.可以对线程的生命周期和执行策略进行管理.
Executor接口
public interface Executor { void execute(Runnable command); }
Executor框架是靠ThreadPoolExecutor实现的,简单理解为是一个线程池.其实是通过线程池和一个阻塞队列BlockingQueue<Runnable>对线程进行管理.
页面渲染器实例
该实例要实现2个任务,第一是渲染文本(速度快),第二个是渲染图片(速度慢).渲染图片的时候要先下载图片才能渲染.
1.第一种方式:顺序执行页面渲染
public class SingleThreadRenderer { public void renderPage(CharSequence source) { renderText(source);// 处理文本,速度快 List<ImageData> imageData = new ArrayList<>(); for (ImageInfo info : scanForImageInfo(source)) { imageData.add(info.downloadImage());// 下载图片,速度慢 } for (ImageData data : imageData) { renderImage(data);// 处理图片 } } }
这种实现方式简单,但是缺点也很明显,就是渲染文本和渲染图片不能并发执行,CPU利用率低.
2.第二种方式:使用Future实现页面渲染器
Future可以持有异步并发线程的执行结果,Executors可以对线程执行并发操作.
public class FutureRenderer { private final ExecutorService exec = Executors.newFixedThreadPool(Runtime
.getRuntime().availableProcessors()); public void renderPage(CharSequence source) {
final List<ImageInfo> imageInfos = scanForImageInfo(source); Callable<List<ImageData>> task = new Callable<List<ImageData>>() {
public List<ImageData> call() throws Exception {
List<ImageData> imageData = new ArrayList<>();
for (ImageInfo info : imageInfos) {
imageData.add(info.downloadImage());// 下载图片,速度慢
}
return imageData;
}
}; Future<List<ImageData>> f = exec.submit(task);
//渲染图片的线程正在执行的同时处理文本任务
renderText(source);// 处理文本,速度快 try {
List<ImageData> imageDatas = f.get(); for (ImageData data : imageDatas) {
renderImage(data);// 处理图片
}
} catch (InterruptedException | ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} }
}
这种执行策略仍旧有局限性,这是由于并行运行异类任务并不会获得好的性能.只有大量相互独立的且同类的任务进行并发处理,才能获得真正性能提升.
3.第三种方式:使用CompletionService的页面渲染器
public class CompletionServiceRenderer {
private final ExecutorService exec = Executors.newFixedThreadPool(Runtime
.getRuntime().availableProcessors()); public void renderPage(CharSequence source) { final List<ImageInfo> imageInfos = scanForImageInfo(source); CompletionService<ImageData> completionService = new ExecutorCompletionService<>(
exec); for (final ImageInfo info : imageInfos) {
Callable<ImageData> task = new Callable<ImageData>() {
public ImageData call() throws Exception {
return info.downloadImage();
}
};
completionService.submit(task);
} renderText(source);// 处理文本,速度快 for (int i = 0; i < imageInfos.size(); i++) {
try {
Future<ImageData> future = completionService.take();
ImageData imageData = future.get();
renderImage(imageData);// 处理图片 } catch (InterruptedException | ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} } }
}
这种方式不用等下载所有图片才处理,而是每下载一张图片就处理,实现了很好的并发行.
Java并发编程实践(读书笔记) 任务执行(未完)的更多相关文章
- Java并发编程实践读书笔记(3)任务执行
类似于Web服务器这种多任务情况时,不可能只用一个线程来对外提供服务.这样效率和吞吐量都太低. 但是也不能来一个请求就创建一个线程,因为创建线程的成本很高,系统能创建的线程数量是有限的. 于是Exec ...
- Java并发编程实践读书笔记(5) 线程池的使用
Executor与Task的耦合性 1,除非线程池很非常大,否则一个Task不要依赖同一个线程服务中的另外一个Task,因为这样容易造成死锁: 2,线程的执行是并行的,所以在设计Task的时候要考虑到 ...
- Java并发编程实践读书笔记(2)多线程基础组件
同步容器 同步容器是指那些对所有的操作都进行加锁(synchronize)的容器.比如Vector.HashTable和Collections.synchronizedXXX返回系列对象: 可以看到, ...
- Java并发编程实践读书笔记(1)线程安全性和对象的共享
2.线程的安全性 2.1什么是线程安全 在多个线程访问的时候,程序还能"正确",那就是线程安全的. 无状态(可以理解为没有字段的类)的对象一定是线程安全的. 2.2 原子性 典型的 ...
- Java并发编程实践读书笔记(4)任务取消和关闭
任务的取消 中断传递原理 Java中没有抢占式中断,就是武力让线程直接中断. Java中的中断可以理解为就是一种简单的消息机制.某个线程可以向其他线程发送消息,告诉你“你应该中断了”.收到这条消息的线 ...
- Java并发编程实战 读书笔记(二)
关于发布和逸出 并发编程实践中,this引用逃逸("this"escape)是指对象还没有构造完成,它的this引用就被发布出去了.这是危及到线程安全的,因为其他线程有可能通过这个 ...
- Java并发编程实战 读书笔记(一)
最近在看多线程经典书籍Java并发变成实战,很多概念有疑惑,虽然工作中很少用到多线程,但觉得还是自己太弱了.加油.记一些随笔.下面简单介绍一下线程. 一 线程与进程 进程与线程的解释 个人觉 ...
- Java并发编程艺术读书笔记
1.多线程在CPU切换过程中,由于需要保存线程之前状态和加载新线程状态,成为上下文切换,上下文切换会造成消耗系统内存.所以,可合理控制线程数量. 如何控制: (1)使用ps -ef|grep appn ...
- Java并发编程实践
最近阅读了<Java并发编程实践>这本书,总结了一下几个相关的知识点. 线程安全 当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任 ...
随机推荐
- Apple Swift学习资料汇总
今年的苹果开发者大会(WWDC)上,公布了ios8的几个新特性,其中包括引入了群聊功能,支持第三方输入法等功能.但更让开发者感兴趣的莫过于Swift语言的发布了. Swift是apple自创的一门转为 ...
- java中,Date数据类型和JSONObject数据类型之间的转换
import java.text.SimpleDateFormat;import java.util.Date;import net.sf.json.JSONObject; public class ...
- Your build settings specify a provisioning profile with the UUID, no such provisioning profile was found的解决方案
在Archive项目时,出现了“Your build settings specify a provisioning profile with the UUID “”, however, no suc ...
- nginx 禁止非指定域名访问
nginx 配置如下: server { listen 80 default_server; server_name _; return 404; } # server conf server { l ...
- mysql 更新 语句中 的 safe_mode
在mysql5中,可以设置safe mode,比如在一个更新语句中UPDATE table_name SET bDeleted=0;执行时会错误,报:You are using safe update ...
- CSS自学笔记(13):CSS3 2D/3D转换
CSS3中新增了对元素进行2D和3D的转换效果,这样可以是开发人员很方便的做出视觉效果更好的网页来. 通过CSS3中属性的定义,我们可以对元素进行移动.缩放.拉伸.旋转等等,可以通过定义transfo ...
- arrowTip 提示
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 论山寨手机与Android联姻 【10】SmartPhone的通信机制
上一章我们说到,智能手机 == 电脑 + 移动网卡,这个提法比较粗略,更精准的提法应当是,智能手机的硬件结构分为应用程序处理器AP,和基带处理器BP两个部分.虽然AP部分的功能与电脑主板基本类似,但是 ...
- 解决Delphi自带UTF8解码缺陷(使用API)
因为Delphi自带的转换函数遇到其无法识别的字符串就返回空,下面函数可解决该问题. function DecodeUtf8Str(const S: UTF8String): WideString;v ...
- SQL Server创建LinkServer
USE [master] GO /****** Object: LinkedServer [xxx_LNK] Script Date: 2014/7/7 17:04:13 ******/ EXEC m ...