zoukankan      html  css  js  c++  java
  • 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();
                }
    
            }
    
        }
    }


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

     

     

  • 相关阅读:
    高德地图API,获取和设置zoom级别和中心点
    高德地图API注册使用教程简答演示
    HTML5 视频流行插件之video.js
    audio实现自定义音频播放器
    HTML5 audio API事件
    HTML5之audio属性
    GitLab的安装及使用教程
    设计模式六大原则(PHP)
    面向对象设计
    自定义的异常类
  • 原文地址:https://www.cnblogs.com/csu_xajy/p/4260388.html
Copyright © 2011-2022 走看看