Future 解析与使用

Java 1.5开始, 提供了 CallableFuture, 通过它们可以在任务执行完毕之后得到任务执行结果.

当需要调用几个执行很慢的方法时, 可以使用多线程一起执行这几个方法, 等所有方法执行完毕后得到执行结果, 在进行别的处理.

Future 的主要方法

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

get() 方法可以当任务结束后返回一个结果, 如果调用时, 工作还没有结束, 则会阻塞线程, 直到任务执行完毕.

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

cancel(boolean mayInterruptIfRunning) 方法可以用来停止一个任务.

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

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 ft1 = new FutureTask(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 ft2 = new FutureTask(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 f = mExecutor.submit(new Callable() {
            @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 titleList = new ArrayList();
            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 会获取到异常的信息.

你可能感兴趣的:(多线程,java)