首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

改进并发性能-JCIP6.3读书笔记

2012-08-31 
改善并发性能--JCIP6.3读书笔记[本文是我对Java Concurrency In Practice 6.3的归纳和总结. ?转载请注明作

改善并发性能--JCIP6.3读书笔记

[本文是我对Java Concurrency In Practice 6.3的归纳和总结. ?转载请注明作者和出处, ?如有谬误, 欢迎在评论中指正. ]

浏览器的页面渲染模块负责HTML标记的处理, 本文以页面渲染为例探讨线程与并发. 为了简化问题, 我们假设只包含文本标记和图片标记.

?

单线程渲染

使用单线程处理是最简单的方式: 从头至尾扫描HTML文件, 如果遇到文本标记, 将其写入缓冲. 如果遇到图片标记, 就从Internet上下载后将其写入缓冲. 处理完整个文件之后, 将结果呈现给用户. 如果图片的下载速度很慢, 可能需要让用户等待很长时间. 因此我们对上述的渲染器进行简单的优化: 遇到图片标记, 就记录其下载地址, 并使用矩形的占位符. 处理完文件后先将结果呈现给用户, 然后再从Internet上下载图片, 图片下载完成就填充到占位符中:

public class Renderer {     private final ExecutorService executor;      Renderer(ExecutorService executor) { this.executor = executor; }      void renderPage(CharSequence source) {         final List<ImageInfo> info = scanForImageInfo(source);         CompletionService<ImageData> completionService =             new ExecutorCompletionService<ImageData>(executor);         for (final ImageInfo imageInfo : info)     // 将图片下载拆分为多个任务            completionService.submit(new Callable<ImageData>() {                  public ImageData call() {                      return imageInfo.downloadImage();                  }             });          renderText(source);          try {             for (int t = 0, n =  info.size(); t < n;  t++) { // take方法可能阻塞: 当已完成队列中为空时                Future<ImageData> f = completionService.take(); // get方法不会阻塞, 因为从take方法返回的Future对象肯定是已完成的                ImageData imageData = f.get();                 renderImage(imageData);             }         } catch (InterruptedException e) {             Thread.currentThread().interrupt();         } catch (ExecutionException e) {             throw launderThrowable(e.getCause());         }     } } 
?

Renderer将图片下载拆分成多个任务, 解决了任务的不对称问题. 当图片下载完成后, 会以完成的顺序将Future添加到CompletionService对象的已完成队列中. 调用CompletionService对象的take方法可以从已完成队列中取出Future, 如果队列为空, take方法将阻塞, 直到队列不为空. 因此Renderer对图片的渲染按照下载完成的顺序进行(并非按照提交下载任务的顺序进行). Renderer具有不错的并发性能, 并且改善了渲染的响应速度.

热点排行