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并发编程实践>这本书,总结了一下几个相关的知识点. 线程安全 当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任 ...
随机推荐
- AS3: Socket 数据包 收 发
AS3.0中使用Socket使用tcp服务器协议,它是一种流协议,不停的将分片传输给客户端,P作为流,发包是不会整包到达的,而是源源不断的. 它不同于UDP服务器协议,UDP作为数据包协议,整包到达. ...
- 依赖注入及AOP简述(十)——Web开发中常用Scope简介 .
1.2. Web开发中常用Scope简介 这里主要介绍基于Servlet的Web开发中常用的Scope. l 第一个比较常用的就是Application级Scope,通常我们会将一 ...
- 在Activity中动态设置TextView的隐藏属性
if (true) { //显示 viewHolder.tvLine.setVisibility(View.INVISIBLE);} else { //不显示 viewHolder.tvLine.se ...
- Oracle利用过程procedure块实现银行转账
-- create table account( id ) not null, name ), ,2), constraint a_pk primary key(id) ); --历史表 select ...
- 浅谈:配置本地yum源(centos)
删除YUM的所有配置信息[root@server yum.repos.d]#rm -rf * 现在手动配置:1.在根目录下创建文件夹centos-yum: [root@server /]#mkdir ...
- hdu1281棋盘游戏
Problem Description 小希和Gardon在玩一个游戏:对一个N*M的棋盘,在格子里放尽量多的一些国际象棋里面的“车”,并且使得他们不能互相攻击,这当然很简单,但是Gardon限制了只 ...
- slice,substr,substring
var s = '0123456789'; //slice 遇负数,则此负数值等同于 s.length + (负数) s.slice(3,6); //"345", 从位置3开始 ...
- DOM的认识以及一些节点的应用
HTML DOM (文档对象模型) 当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model). HTML DOM 模型被构造为对象的树. HTML DOM 树 通过 ...
- 前端开发面试题收集 HTML
Doctype是什么?说明特点. <!doctype>声明必须处于HTML文档的头部,在标签之前. <!doctype>声明不是一个HTML标签,是一个用于告诉浏览器使用哪种H ...
- jquery ajax提交及请求
jQuery.ajax({ url: dataURL, success: function(results) { var parsedJson = jQuery.parseJSON(results); ...