通过多次优化实例来了解选择并发策略的正确姿势

  通过模拟浏览器程序的渲染页面(Page-Rendering)功能,为了方便,假设HTML页面只会包含标签文本和图片以及URL;

  

  第一个版本:串行加载页面元素

public class SingleThreadRenderer{
void renderPage(CharSequence source){
renderText(Source);
List<ImageData> imageData = new ArrayList<ImageData>();
for(ImageInfo imageInfo : scanForImageInfo(source))
imageData.add(imageInfo.downloadImage());
for(ImageData data : ImageData)
renderImage(data);
}
}

  存在的问题:浏览器加载图片之前需要下载图片,此时如果存在网络拥塞,那么此时的CPU几乎没怎么用,大都在等待I/O操作执行完成,也会使用户体验降低:图片没下载完,文字就加载不出来;

  改进版本1:使用Future实现页面渲染

/**
* @author YHW
* @ClassName: FutureRenderer
* @Description:
* @date 2019/3/28 16:21
*/
public class FutureRenderer {
private ExecutorService executor ; void renderPage(CharSequence source){
final List<ImageInfo> imageInfos = scanForImageInfo(source);
Callable<list<ImageData>> task = new Callable<list<ImageData>>(){
public List<ImageData> call(){
List<ImageData> result = new ArrayList<ImageData>();
for(ImageInfo imageInfo : imageInfos)
result.add(imageInfo.downloadImage());
return result;
}
}; Future<List<ImageData>> future = executor.submit(task);
renderText(source); try{
List<ImageData> imageData = future.get();
for(ImageData data : imageData){
renderImage(data);
}
}catch(InterruptedException e){
Thread.currentThread().interrupt();
future.cancel(true);
}catch(ExecutionException e){
throw launderThrowable(e.getCause());
}
}
}

  该版本使得页面文本和图片实现异步加载,但还有可以优化的地方,假设渲染文本的速度远大于图片的下载速度(很有可能),那么该版本与串行程序最后的性能差别不大,所以此改进方法对于性能的提升非常有限,而代码却更加复杂,其实在大量相互独立且同构的任务可以并发进行处理时,才能体现出将程序的负载分配带来真正的性能提升;

  改进版本2:使用完成服务(CompletionService),其基于Executor和BlockingQueue,可以将Callable任务交给它来执行,再使用类似队列的出队操作来获取结果:

public class Renderer {
private final ExecutorService executor; Renderer(ExecutorService executor){ this.executor = executor; } void revderPage(Charquence source){
List<ImageInfo> info = scanForImageInfo(source);
CompletionService<ImageData> completionService = new ExecutorComplementService<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++){
Future<ImageData> f = completionService.take():
ImageData imageData = f.get();
renderImage(imageData);
}
}catch(InterruptedException e){
Thread。currentThread().interrupt();
}catch(ExecutionException e){
throw launderThrowbale(e.getCause());
}
}
}

  经过第二次的改进,页面更加“响应式”,每个图片都会在下载完成后直接加载渲染至页面,同时异步加载HTML中的文本和URL,使用户获得更加动态的界面;

Java并发(六):并发策略的更多相关文章

  1. java处理高并发高负载类网站的优化方法

    java处理高并发高负载类网站中数据库的设计方法(java教程,java处理大量数据,java高负载数据) 一:高并发高负载类网站关注点之数据库 没错,首先是数据库,这是大多数应用所面临的首个SPOF ...

  2. [转]java处理高并发高负载类网站的优化方法

    本文转自:http://www.cnblogs.com/pengyongjun/p/3406210.html java处理高并发高负载类网站中数据库的设计方法(java教程,java处理大量数据,ja ...

  3. java之高并发与多线程

    进程和线程的区别和联系 从资源占用,切换效率,通信方式等方面解答 线程具有许多传统进程所具有的特征,故又称为轻型进程(Light—Weight Process)或进程元:而把传统的进程称为重型进程(H ...

  4. JAVA多线程和并发基础面试问答(转载)

    JAVA多线程和并发基础面试问答 原文链接:http://ifeve.com/java-multi-threading-concurrency-interview-questions-with-ans ...

  5. [转] JAVA多线程和并发基础面试问答

    JAVA多线程和并发基础面试问答 原文链接:http://ifeve.com/java-multi-threading-concurrency-interview-questions-with-ans ...

  6. JAVA多线程和并发基础面试问答

    转载: JAVA多线程和并发基础面试问答 多线程和并发问题是Java技术面试中面试官比较喜欢问的问题之一.在这里,从面试的角度列出了大部分重要的问题,但是你仍然应该牢固的掌握Java多线程基础知识来对 ...

  7. 【多线程】JAVA多线程和并发基础面试问答(转载)

    JAVA多线程和并发基础面试问答 原文链接:http://ifeve.com/java-multi-threading-concurrency-interview-questions-with-ans ...

  8. Java 多线程 (并发)总结

    一.概念 1. 维基百科解释 进程是什么? http://zh.wikipedia.org/wiki/%E8%BF%9B%E7%A8%8B 线程是什么? http://zh.wikipedia.org ...

  9. (转)JAVA多线程和并发基础面试问答

    JAVA多线程和并发基础面试问答 原文链接:http://ifeve.com/java-multi-threading-concurrency-interview-questions-with-ans ...

随机推荐

  1. 基于OpenCV之视频读取,处理和显示框架的搭建(一)

    主要包括以下内容: 1.使用的主要函数的说明. 2.两个实例:视频读取和显示.搭建视频读取和处理框架,调用canny函数提取边缘并显示. 3.一些注意事项和代码说明. 一.使用的主要函数 1.延时函数 ...

  2. 菜鸟攻城狮1(JAVA程序设计)

    1.JAVA是一个完整的平台,有一个庞大的库,提供了可重复利用的代码功能块,安全性,跨操作系统的可以移植性,自动垃圾回收机制 2.JAVA设计者白皮书:简单性.面向对象.网络技能.健壮性.安全性.体系 ...

  3. Windchill 查询功能

    一.使用SearchCondition 查询语句中用容器中的containerReference.key.id名称来代替数据库中的字段idA3containerReference /**      * ...

  4. Ubuntu 12.04 LTS为例演示vsftpd虚拟用户 的配置

    vsftpd虚拟用户   2012-05-19 15:46:59|  分类: GNU/Linux |  标签:ubuntu  vsftpd  ftp  虚拟用户  |举报|字号 订阅 我们登录FTP有 ...

  5. 7.31实习培训日志-docker sql

    docker mysql docker问题 今天问了老师有关docker的问题,entrypoint和cmd的区别,两者同时存在cmd的执行结果会被当做参数传入entrypoint. dockerfi ...

  6. 项目:IT资源共享资源(登录后端)<2>

    公众号技术标签 小程序 PHP 源码 项目 ThinkPHP5.0目录结构,新建一个模块api,该模块下面有controller.model 目录,前者放控制器,写API接口(这里是简单的api写法) ...

  7. Boost Python学习笔记(二)

    你将学到什么 如何在Python中调用C++代码 如何在C++中调用Python代码 在Python中调用C++代码 首先定义一个动物类(include/animal.h) #pragma once ...

  8. 洛谷P1480 A/B Problem(高精除高精)

    P1480 A/B Problem 题目描述 输入两个整数a,b,输出它们的商(a<=10^5000,b<=10^9) 输入输出格式 输入格式: 两行,第一行是被除数,第二行是除数. 输出 ...

  9. 2017-10-17 NOIP模拟赛

    Reverse #include<iostream> #include<cstdio> #include<cstring> using namespace std; ...

  10. 对不起,给pandas配表情包太难了,pandas你该这么学,No.6

    如果图片无法观看,请移步 https://blog.csdn.net/hihell 标题起的长,才能引起你的注意呢 昨天,有个家伙,留言给我说 嫌我不好好写博客 就知道给文章配表情包 在这里,郑重的回 ...