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并发编程实践>这本书,总结了一下几个相关的知识点. 线程安全 当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任 ...
随机推荐
- H面试程序(11): 判断字符串是否包含子串问题
题目描述: 如字符串str1为''abcdef''' 字符串str2为'' bc''; 则字符串str1中含有 ...
- android之存储篇_存储方式总览
作为一个完成的应用程序,数据存储操作是必不可少的.因此,Android系统一共提供了四种数据存储方式.分别是:SharePreference.SQLite.Content Provider和File. ...
- docker相关配置
一.概述: 1.centos7下,默认firewalld为防火墙, systemctl status firewalld.service 2.关闭firewalld, systemctl stop f ...
- 关于js对象值的传递
结合红宝书和网上的一些文章,记录下自己对关于js对象的值的传递的一些理解. js对象是保存在堆内存中的,当把对象赋值给变量时,是把对象在堆内存的引用(地址)赋值给了变量,变量通过地址来访问对象.下面来 ...
- VS2012 黑色护眼主题
在黑色主题基础上,更改了字体 Ms Comic Sans 字号也增大了 附件中有两个 一个是原版主题下载自https://studiostyl.es/ 第二个是如下改完后的主题 vssettings. ...
- Database name和SID
http://docs.oracle.com/cd/B19306_01/install.102/b15667/rev_precon_db.htm#i1027493 The Oracle Databas ...
- SQL性能优化的思路建议
如何在 Oracle数据库里写出高质量的SQL语句,如何在Oracle数据库里对有性能问题的SQL做诊断和调整,这是DBA们在ORACLE数据库实践中不可避免的难题.下面就让我们来分析一下拿到一条问题 ...
- 去掉UItableview headerview黏性
//去掉UItableview headerview黏性 - (void)scrollViewDidScroll:(UIScrollView *)scrollView { if (scrollView ...
- OC——NSString的常用方法
NSString *str1 = @"BeiJing"; NSString *str2 = @"beijing"; //全部转为大写 NSLog(@" ...
- Java面试题整理(题目内容非原创)
面试题分类: 1.java 基础面试题 Java基础中对于io 中文件的读.写,util中的list map set这些要分清楚 还有线程.socket 都需要了解下 参考链接:http://blog ...