Future 解析与使用

Java 1.5开始, 提供了 CallableFuture, 经过它们能够在任务执行完毕以后获得任务执行结果.多线程

当须要调用几个执行很慢的方法时, 可使用多线程一块儿执行这几个方法, 等全部方法执行完毕后获得执行结果, 在进行别的处理.dom

Future 的主要方法ide

Future 接口主要包括 5 个方法:spa

clipboard.png

get() 方法能够当任务结束后返回一个结果, 若是调用时, 工做尚未结束, 则会阻塞线程, 直到任务执行完毕.线程

get(long timeout,TimeUnit unit) 作多等待 timeout 的时间就会返回结果.3d

cancel(boolean mayInterruptIfRunning) 方法能够用来中止一个任务.code

isDone() 方法判断当前方法是否完成.blog

isCancel() 方法判断当前方法是否取消.接口

Future 示例 demo游戏

需求场景: 等早餐过程当中, 包子须要 3 秒, 凉菜须要 1 秒, 普通的多线程须要四秒才能完成. 先等凉菜, 再等包子, 由于等凉菜时, 普通多线程启动 start() 方法, 执行 run() 中具体方法时, 没有返回结果, 因此若是要等有返回结果, 必须是要1秒结束后才知道结果.

public static void main(String[] args) throws InterruptedException, ExecutionException {
        long start = System.currentTimeMillis();

        // 等凉菜 
        Callable ca1 = new Callable() {
            @Override
            public String call() throws Exception {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return "凉菜准备完毕";
            }
        };
        FutureTask<String> ft1 = new FutureTask<String>(ca1);
        new Thread(ft1).start();

        // 等包子 -- 必需要等待返回的结果,因此要调用join方法
        Callable ca2 = new Callable() {

            @Override
            public Object call() throws Exception {
                try {
                    Thread.sleep(1000 * 3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return "包子准备完毕";
            }
        };
        FutureTask<String> ft2 = new FutureTask<String>(ca2);
        new Thread(ft2).start();

        System.out.println(ft1.get());
        System.out.println(ft2.get());

        long end = System.currentTimeMillis();
        System.out.println("准备完毕时间:" + (end - start));
    }

还有一个比较典型的例子就是设置超时时间:

//固定大小的线程池,同时只能接受5个任务
    static ExecutorService mExecutor = Executors.newFixedThreadPool(5);
    final static long timeout = 4 ;

    /**
     * 模拟在预约时间内获取广告信息
     * @throws InterruptedException
     */
    static void rederPageWithAd(final String pageTitle)  throws  InterruptedException{
        Future<String> f = mExecutor.submit(new Callable<String>() {
            @Override
            public String call() throws Exception {
                System.out.println("开始加载广告信息");
                int randomTime = new Random().nextInt(5) + 1;//限制耗时不会出现0s,不会大于10s
                Thread.sleep(100 * 1000);
                System.out.println("正常加载广告耗时:" + randomTime +"s");
                return pageTitle;
            }
        });

        String page;
        try {
            //在预计时间内等待
            System.out.println("预期任务执行完时间:" + timeout + "s");
            //page = f.get();
            page = f.get(timeout, TimeUnit.SECONDS);
        } catch (ExecutionException e) {
            page = "出现执行异常,显示默认的广告页面";
        } catch (TimeoutException e) {
            page = "任务执行超时,显示默认的广告页面";
            f.cancel(true);//取消没有执行完的任务,设置为ture说明任务能被中断,不然执行中的任务要完成
        }
        System.out.println("成功加载广告页面:" + page);


    }


    public static void main(String[] args) {
        try {
            List<String> titleList = new ArrayList<String>();
            titleList.add("体育赛事");
            titleList.add("娱乐新闻");
            titleList.add("实时聚焦");
            titleList.add("国际咨询");
            titleList.add("影视天下");
            titleList.add("游戏风云");
            for (String string : titleList) {
                rederPageWithAd(string);
            }

        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally{
            /**
             * 只有执行了shutdown方法,执行isTerminated才有效。不然isTerminated一直为ture
             */
            mExecutor.shutdown();
            while(true){
                if(mExecutor.isTerminated()){
                    System.out.println("全部任务都执行完了,关闭线程池");
                    break;
                }
            }
        }

    }

值得注意的是: 当主线程调用 Futureget 方法的时候会获取到从线程中返回的结果数据. 若是在线程的执行过程当中发生了异常, get 会获取到异常的信息.

相关文章
相关标签/搜索