首页 技术 正文
技术 2022年11月20日
0 收藏 396 点赞 2,724 浏览 2728 个字

任务的定义

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

 

任务的执行策略

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();
} } }
}


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

 

 

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,488
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,903
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,736
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,487
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:8,127
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:5,289