zoukankan      html  css  js  c++  java
  • 任务执行

      大多数并发应用程序都是围绕“任务执行(Task  Execution)”来构造的:任务通常是一些抽象的且离散的工作单元。

      在生产环境中,“为每个任务分配一个线程”这种方法存在一些缺陷,尤其是当需要创建大量线程时:

    • 线程生命周期的开销非常高。线程的创建与销毁并不是没有代价的。
    • 资源消耗。活跃的线程会消耗系统资源,尤其是内存。  
    • 稳定性。在可创建线程的数量上存在一个限制。

      在一定范围内,增加线程可以提高系统的吞吐率,但如果超出了这个范围,再创建更多的线程只会降低程序的执行速度,并且如果过多地创建一个线程,那么整个应用程序将崩溃,要想避免这种危险,就应该对应用程序可以创建的线程数量进行限制,并且全面的测试应用程序,从而确保在线程数量达到限制时,程序也不会耗尽资源。

      在Java类库中,任务执行的主要抽象不是Thread,而是Executor。虽然Executor是个简单的接口,但它却为灵活且强大的异步任务执行框架提供了基础,该框架能支持多种不同类型的任务执行策略。它提供了一种标准的方法将任务的提交过程与执行过程解耦开来,并用Runnable来表示任务。Executor的实现还提供了对生命周期的支持,以及统计信息收集、应用程序管理机制和性能监视等机制。

      Executor基于生产者-消费者模式,提交任务的操作相当于生产者(生产待完成的工作单元),执行任务的线程则相当于消费者(执行完这些工作单元)。如果要在程序中实现一个生产者-消费者的设计,那么最简单的方式通常就是使用Executor。

      

    public class TaskExecutionWebServer {
        private static final int NTHREADS = 100;
        private static final Executor exec = Executors.newFixedThreadPool(NTHREADS);
    
        public static void main(String[] args) throws IOException{
            ServerSocket serverSocket = new ServerSocket(80);
            while (true){
                final Socket connection = serverSocket.accept();
                Runnable task = new Runnable() {
                    @Override
                    public void run() {
                        handleRequest(connection);
                    }
                };
                exec.execute(task);
            }
        }
    }

      线程池,从字面啊啊含义来看,是指管理一组同构工作线程的资源池。线程池是与工作队列密切相关的,其中在工作队列中保存了所有等待执行的任务。工作者线程的任务很简单:从工作队列中获取一个任务,执行任务,然后返回线程池并等待下一个任务。

      为了解决执行服务的生命周期问题,Executor扩展了ExecutorService接口,添加了一些用于生命周期管理的方法(同时还有一些用于任务提交的便利方法)。ExecutorService的生命周期有3种状态:运行、关闭和已终止。ExecutorService在初始创建时处于运行状态。shutdown方法将执行平缓的关闭过程:不再接受新的任务,同时等待已经提交的任务执行完成——包括哪些还未开始执行的任务。shutdownNow方法将执行粗暴的关闭过程:它将尝试取消所有运行中的任务,并且不再启动队列中尚未开始执行的任务。

      CompletionService将Executor和BlockingQueue的功能融合在一起。你可以将Callable任务提交给它来执行,然后使用类似于队列操作的take和poll等方法来获得已完成的结果,而这些结果会在完成时将被封装为Future。ExecutorCompletionService实现了CompletionService,并将计算部分委托给一个Executor。

    public class Renderer {
        private final ExecutorService executorService;
    
        Renderer(ExecutorService executorService){
            this.executorService = executorService;
        }
    
        void renderPage(CharSequence source){
            List<ImageInfo> info = scanForImageInfo(source);
            CompletionService<ImageData> completionService =
                    new ExecutorCompletionService<ImageData>(executorService);
            for (final ImageInfo imageInfo:info){
                completionService.submit(new Callable<ImageData>() {
                    @Override
                    public ImageData call() throws Exception {
                        return imageInfo.downloadImage();
                    }
                });
            }
            renderText(source);
    
            try{
                for (int i=0;i<info.size();i++){
                    Future<ImageData> f = completionService.take();
                    ImageData imageData = f.get();
                    renderImage(imageData);
                }
            } catch (InterruptedException e){
                e.printStackTrace();
            } catch (ExecutionException e){
                e.printStackTrace();
            }
    
        }
    }

      有时候,如果某个任务无法在指定时间内完成,那么将不再需要它的结果,此时可以放弃这个任务。例如,某个web应用程序从外部的广告服务器上获取广告信息,但如果该应用程序在两秒内得不到响应,那么将显示一个默认的广告,这样即使不能获得广告信息,也不会降低站点的响应性能。在支持时间限制的Future.get中支持这种需求:当结果可用时,它将立即返回,如果在执行时间内没有计算出结果,那么将抛出TimeoutException。

      

    public List<TravelQuote> getRankedTravelQuotes(TravelInfo travelInfo,
                                                      Set<TravelCompany> companies,
                                                      Comparator<TravelQuote> ranking,long time,
                                                      TimeUnit unit)throws InterruptedException{
           List<QuoteTask> tasks = new ArrayList<QuoteTask>();
           for (TravelCompany company:companies){
               tasks.add(new QuoteTask(company,travelInfo));
           }
    
           List<Future<TravelQuote>> futures = executorService.invokeAll(tasks,time,unit);
    
           List<TravelQuote> quotes = new ArrayList<TravelQuote>(tasks.size());
           Iterator<QuoteTask> taskIterator = tasks.iterator();
    
           for (Future<TravelQuote> f:futures){
               QuoteTask task = taskIterator.next();
               try {
                   quotes.add(f.get());
               } catch (ExecutionException e){
                   quotes.add(task.getFailureQuote(e.getCause()));
               }catch (CancellationException e){
                   quotes.add(task.getTimeoutQuote(e));
               }
           }
    
           Collections.sort(quotes,ranking);
           return quotes;
       }
  • 相关阅读:
    jmeter实现multipart/form-data类型请求
    jmeter(正则提取器、json提取器)做接口关联
    windows使用ubuntu启动linux服务
    Jmeter+Ant+Jenkins环境搭建
    ubuntu网卡驱动的安装
    Ubuntu 挂载U盘
    Linux下安装jdk8步骤详述(转载)
    springboot项目:项目部署
    springboot项目:Redis缓存使用
    springboot项目:Redis分布式锁的使用(模拟秒杀系统)
  • 原文地址:https://www.cnblogs.com/lsf90/p/3737959.html
Copyright © 2011-2022 走看看