任务的定义

大多数并发程序都是围绕任务进行管理的.任务就是抽象和离散的工作单元.

 

任务的执行策略

1.顺序的执行任务

这种策略的特点是一般只有按顺序处理到来的任务.一次只能处理一个任务,后来其它任务都要等待处理.响应性很糟糕,吞吐量低.系统资源利用率低.

2.显示的为任务创建线程

为每个任务创建对应一个线程,响应快,系统资源利用路高.缺点是资源消耗量大,如果有大量任务要执行的话,系统迟早会因为无限制创建过多的线程而造成内存耗尽.特别当创建的线程数量远远大于系统的CPU核数,由于每一个核同一时刻只能执行一个线程,所以系统要执行很多不必要的线程上下文切换,造成资源大量浪费.

3.Executor框架

Executor接口本身很简单,就一个execute方法.但是由Executor这个接口衍生出来的类,功能非常强大.可以这么认为,Executor框架这是线程管理的工具.可以对线程的生命周期和执行策略进行管理.

Executor接口

  1. public interface Executor {
  2.  
  3. void execute(Runnable command);
  4.  
  5. }

Executor框架是靠ThreadPoolExecutor实现的,简单理解为是一个线程池.其实是通过线程池和一个阻塞队列BlockingQueue<Runnable>对线程进行管理.

页面渲染器实例


该实例要实现2个任务,第一是渲染文本(速度快),第二个是渲染图片(速度慢).渲染图片的时候要先下载图片才能渲染.

1.第一种方式:顺序执行页面渲染

  1. public class SingleThreadRenderer {
  2.  
  3. public void renderPage(CharSequence source) {
  4.  
  5. renderText(source);// 处理文本,速度快
  6.  
  7. List<ImageData> imageData = new ArrayList<>();
  8.  
  9. for (ImageInfo info : scanForImageInfo(source)) {
  10.  
  11. imageData.add(info.downloadImage());// 下载图片,速度慢
  12.  
  13. }
  14.  
  15. for (ImageData data : imageData) {
  16.  
  17. renderImage(data);// 处理图片
  18.  
  19. }
  20.  
  21. }
  22.  
  23. }

这种实现方式简单,但是缺点也很明显,就是渲染文本和渲染图片不能并发执行,CPU利用率低.

2.第二种方式:使用Future实现页面渲染器

Future可以持有异步并发线程的执行结果,Executors可以对线程执行并发操作.

 

  1. public class FutureRenderer {
  2.  
  3. private final ExecutorService exec = Executors.newFixedThreadPool(Runtime
  4. .getRuntime().availableProcessors());
  5.  
  6. public void renderPage(CharSequence source) {
  7. final List<ImageInfo> imageInfos = scanForImageInfo(source);
  8.  
  9. Callable<List<ImageData>> task = new Callable<List<ImageData>>() {
  10. public List<ImageData> call() throws Exception {
  11. List<ImageData> imageData = new ArrayList<>();
  12. for (ImageInfo info : imageInfos) {
  13. imageData.add(info.downloadImage());// 下载图片,速度慢
  14. }
  15. return imageData;
  16. }
  17. };
  18.  
  19. Future<List<ImageData>> f = exec.submit(task);
  20. //渲染图片的线程正在执行的同时处理文本任务
  21. renderText(source);// 处理文本,速度快
  22.  
  23. try {
  24. List<ImageData> imageDatas = f.get();
  25.  
  26. for (ImageData data : imageDatas) {
  27. renderImage(data);// 处理图片
  28. }
  29. } catch (InterruptedException | ExecutionException e) {
  30. // TODO Auto-generated catch block
  31. e.printStackTrace();
  32. }
  33.  
  34. }
    }

这种执行策略仍旧有局限性,这是由于并行运行异类任务并不会获得好的性能.只有大量相互独立的且同类的任务进行并发处理,才能获得真正性能提升.

3.第三种方式:使用CompletionService的页面渲染器

 

  1. public class CompletionServiceRenderer {
  2. private final ExecutorService exec = Executors.newFixedThreadPool(Runtime
  3. .getRuntime().availableProcessors());
  4.  
  5. public void renderPage(CharSequence source) {
  6.  
  7. final List<ImageInfo> imageInfos = scanForImageInfo(source);
  8.  
  9. CompletionService<ImageData> completionService = new ExecutorCompletionService<>(
  10. exec);
  11.  
  12. for (final ImageInfo info : imageInfos) {
  13. Callable<ImageData> task = new Callable<ImageData>() {
  14. public ImageData call() throws Exception {
  15. return info.downloadImage();
  16. }
  17. };
  18. completionService.submit(task);
  19. }
  20.  
  21. renderText(source);// 处理文本,速度快
  22.  
  23. for (int i = 0; i < imageInfos.size(); i++) {
  24. try {
  25. Future<ImageData> future = completionService.take();
  26. ImageData imageData = future.get();
  27. renderImage(imageData);// 处理图片
  28.  
  29. } catch (InterruptedException | ExecutionException e) {
  30. // TODO Auto-generated catch block
  31. e.printStackTrace();
  32. }
  33.  
  34. }
  35.  
  36. }
  37. }


这种方式不用等下载所有图片才处理,而是每下载一张图片就处理,实现了很好的并发行.

 

 

Java并发编程实践(读书笔记) 任务执行(未完)的更多相关文章

  1. Java并发编程实践读书笔记(3)任务执行

    类似于Web服务器这种多任务情况时,不可能只用一个线程来对外提供服务.这样效率和吞吐量都太低. 但是也不能来一个请求就创建一个线程,因为创建线程的成本很高,系统能创建的线程数量是有限的. 于是Exec ...

  2. Java并发编程实践读书笔记(5) 线程池的使用

    Executor与Task的耦合性 1,除非线程池很非常大,否则一个Task不要依赖同一个线程服务中的另外一个Task,因为这样容易造成死锁: 2,线程的执行是并行的,所以在设计Task的时候要考虑到 ...

  3. Java并发编程实践读书笔记(2)多线程基础组件

    同步容器 同步容器是指那些对所有的操作都进行加锁(synchronize)的容器.比如Vector.HashTable和Collections.synchronizedXXX返回系列对象: 可以看到, ...

  4. Java并发编程实践读书笔记(1)线程安全性和对象的共享

    2.线程的安全性 2.1什么是线程安全 在多个线程访问的时候,程序还能"正确",那就是线程安全的. 无状态(可以理解为没有字段的类)的对象一定是线程安全的. 2.2 原子性 典型的 ...

  5. Java并发编程实践读书笔记(4)任务取消和关闭

    任务的取消 中断传递原理 Java中没有抢占式中断,就是武力让线程直接中断. Java中的中断可以理解为就是一种简单的消息机制.某个线程可以向其他线程发送消息,告诉你“你应该中断了”.收到这条消息的线 ...

  6. Java并发编程实战 读书笔记(二)

    关于发布和逸出 并发编程实践中,this引用逃逸("this"escape)是指对象还没有构造完成,它的this引用就被发布出去了.这是危及到线程安全的,因为其他线程有可能通过这个 ...

  7. Java并发编程实战 读书笔记(一)

    最近在看多线程经典书籍Java并发变成实战,很多概念有疑惑,虽然工作中很少用到多线程,但觉得还是自己太弱了.加油.记一些随笔.下面简单介绍一下线程. 一  线程与进程   进程与线程的解释   个人觉 ...

  8. Java并发编程艺术读书笔记

    1.多线程在CPU切换过程中,由于需要保存线程之前状态和加载新线程状态,成为上下文切换,上下文切换会造成消耗系统内存.所以,可合理控制线程数量. 如何控制: (1)使用ps -ef|grep appn ...

  9. Java并发编程实践

    最近阅读了<Java并发编程实践>这本书,总结了一下几个相关的知识点. 线程安全 当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任 ...

随机推荐

  1. H面试程序(11): 判断字符串是否包含子串问题

    题目描述:                        如字符串str1为''abcdef'''                       字符串str2为'' bc''; 则字符串str1中含有 ...

  2. android之存储篇_存储方式总览

    作为一个完成的应用程序,数据存储操作是必不可少的.因此,Android系统一共提供了四种数据存储方式.分别是:SharePreference.SQLite.Content Provider和File. ...

  3. docker相关配置

    一.概述: 1.centos7下,默认firewalld为防火墙, systemctl status firewalld.service 2.关闭firewalld, systemctl stop f ...

  4. 关于js对象值的传递

    结合红宝书和网上的一些文章,记录下自己对关于js对象的值的传递的一些理解. js对象是保存在堆内存中的,当把对象赋值给变量时,是把对象在堆内存的引用(地址)赋值给了变量,变量通过地址来访问对象.下面来 ...

  5. VS2012 黑色护眼主题

    在黑色主题基础上,更改了字体 Ms Comic Sans 字号也增大了 附件中有两个 一个是原版主题下载自https://studiostyl.es/ 第二个是如下改完后的主题 vssettings. ...

  6. Database name和SID

    http://docs.oracle.com/cd/B19306_01/install.102/b15667/rev_precon_db.htm#i1027493 The Oracle Databas ...

  7. SQL性能优化的思路建议

    如何在 Oracle数据库里写出高质量的SQL语句,如何在Oracle数据库里对有性能问题的SQL做诊断和调整,这是DBA们在ORACLE数据库实践中不可避免的难题.下面就让我们来分析一下拿到一条问题 ...

  8. 去掉UItableview headerview黏性

    //去掉UItableview headerview黏性 - (void)scrollViewDidScroll:(UIScrollView *)scrollView { if (scrollView ...

  9. OC——NSString的常用方法

    NSString *str1 = @"BeiJing"; NSString *str2 = @"beijing"; //全部转为大写 NSLog(@" ...

  10. Java面试题整理(题目内容非原创)

    面试题分类: 1.java 基础面试题 Java基础中对于io 中文件的读.写,util中的list map set这些要分清楚 还有线程.socket 都需要了解下 参考链接:http://blog ...