zoukankan      html  css  js  c++  java
  • 为多个任务设置时限invokeAll

    在有限时间内执行任务的主要困难在于,要确保得到答案的时间不会超过限定的时间,或者在限定的时间内无法获得答案。在支持时间限制的Future.get中支持这种需求;当结果可用时,它将立即返回,如果在指定时限内没有计算出结果,那么将抛出TimeoutException。

    在使用限时任务时需要注意,当这些任务超时后应该立即停止,从而避免为继续计算一个不再使用的结果而浪费计算资源。要实现这个功能,可以由任务本身来管理的它的限定时间,并且在超时后中止执行或取消任务。此时可再次使用Future,如果一个限时的get方法抛出了TimeoutException,那么可以通过Future来取消任务。

    我们思考这么一个例子:

    在某个旅游网站上,门户网站获取并限时来自多条航线,旅店或汽车租赁公司的报价,在获取不同公司报价的过程中,可能会调用web服务,访问数据库,执行一个EDI事务或其他机制。在这种情况下,不宜让页面的响应时间受限于最慢的响应时间,而应该只显示在指定时间内收到的信息。对于没有及时响应的服务提供者,页面可以忽略他们,或者显示一个提示信息。

    从一个公司获得报价的过程与从其他公司获得报价的过程无关,因此可以将获取报价的过程当成一个任务,从而使获得报价的过程能并发执行。

    创建n个任务,将其提交到一个线程池,保留n个Future,并使用限时的get方法通过Future串行地获取每一个结果,这一切都很简单,但还有一个更简单的方法——invokeAll.

    package com.citi.test.mutiplethread.demo5.invokeall;
    
    import java.util.concurrent.Callable;
    
    public class CallableTest implements Callable<Integer> {
        @Override
        public Integer call() throws Exception {
            Thread.sleep((long) (Math.random()*10000));
            return (int) (Math.random()*1000);
        }
    }
    package com.citi.test.mutiplethread.demo5.invokeall;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.CancellationException;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    import java.util.concurrent.TimeUnit;
    
    import com.sun.corba.se.impl.orbutil.threadpool.TimeoutException;
    
    public class TestMain {
        public static void main(String[] args) {
            List<CallableTest> tasks=new ArrayList<CallableTest>();
            for(int i=0;i<10;i++){
                tasks.add(new CallableTest());
            }
            ExecutorService executor=Executors.newCachedThreadPool();
            try {
                List<Future<Integer>> invokeAll = executor.invokeAll(tasks,3,TimeUnit.SECONDS);
                for(Future<Integer> future:invokeAll){
                    System.out.println(future.get());
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }catch (CancellationException e) {
                e.printStackTrace();
                System.out.println("aaa");
            }
            executor.shutdown();
        }
    }

    下面是执行结果。 可以看到当到3秒之后,已经完成了两个任务,其他的都被取消了,最终抛出CancellationException.

    invokeAll 原理:

    使用了支持限时的invokeAll,将多个任务提交到一个ExecutorService并获得结果,invokeAll方法的参数为一组任务,并返回一组Future。这两个集合有着相同的结构。

    invokeAll按照任务集合中迭代器的顺序将所有的Future添加到返回的集合中,从而使调用者能将各个Future与其表示的Callable关联起来。

    当所有任务都执行完毕时,或者调用线程被中断时,又或者超过指定时限时,invokeAll将返回。

    当超过指定时限后,任何还未完成的任务都会取消。

    当invoke返回后,每个任务要么正常的完成,要么被取消,而客户端代码可以调用get或isCancelled来判断究竟是何种情况。

  • 相关阅读:
    点击单元格(LinkToAction)获取Table行号和数据(Table篇一)
    金额和数量不显示0
    自定event事件之全局初始化中自动触发(二)
    自定event事件之手动触发(一)
    Python的requests如何同时post图片二进制流和json数据application/octet-stream
    树莓派点亮LED灯需要几行代码?3行。小孩子都能学会
    50元求解pyqt加载并显示pdf问题
    pyqt5加载pdf文档失败
    建个群,互相关心
    唉,十年前的沙雕照片
  • 原文地址:https://www.cnblogs.com/liumy/p/11651391.html
Copyright © 2011-2022 走看看