Java5线程并发库之CALLABLE(可呼叫的,任务)&FUTURE(未来,期望的)

Callable(可呼叫的,任务)&Future(未来,期望的)

接下来我们讲Callable和Future,这个Callable和Future的作用就是,我们程序启动一个线程,然后那个线程运行完了以后呢,它可以给我们返回结果。我们可以去获得这个线程执行完了以后的结果。以下通过代码来看一看它们的效果:

提交单个Callable线程任务,获得它的返回值

线程池不用线程池的void execute(Runnable command)方法来执行任务,而是用<T> Future<T> submit(Callable<T> task)  方法来提交任务,这个方法专门用于提交一个有返回值的任务。这个任务用Callable对象表示,重写它里面的call方法,就可以把代码放到call方法里面执行,并返回结果。结果的类型是通过泛型声明的。这个任务提交以后会有一个结果,这个结果用Future类型的变量接收。我们可以通过future的get()方法,获取到线程返回的结果。

public class CallableAndFuture {

    /**

     * @param args

     */

    public static void main(String[] args) {

        ExecutorService threadPool = Executors.newSingleThreadExecutor();

        Future<String> future = threadPool.submit(new Callable<String>() {

            public String call() throws Exception {

                Thread.sleep(2000);

                return "hello";

            };

        });

        System.out.println("等待结果");

        try {

            System.out.println("拿到结果:" + future.get());

        } catch (InterruptedException e) {

            e.printStackTrace();

        } catch (Exception e) {

            e.printStackTrace();

        }

    }

}

这个只是目前还不知道有什么使用场景。我有一个任务,交给你去运行,运行完了我确实可以拿到结果,但是,我什么时候能够拿到结果呢?我过一会儿就问一下,有没有结果。这对我来说就没有什么意思,那我还不如不起一个线程,我直接调用一个方法,不开子线程,然后执行,执行完了我得到结果。如果说我启动一个线程的意思就是说,好,你去干,干了以后呢,我忙我的,你忙你的,结果出来了,你告诉我,如果我一天到晚去问你,我还干不干事了呢?那我还不如直接调用你,没必要搞一个新线程。

简单的说,就是有一个Callable的任务,这个任务会返回结果,返回的结果用Future来拿,当结果返回了之后,Future就可以拿到结果了,当future还没有拿到结果的时候,future.get()会一直在那里等,既然是一直在那里等,代码没有办法往下执行,那我干脆调用一个方法,也是一样的,反正也是干不了活,都得等执行完,拿到结果。

好,那没有一种可能就是,我不想等,我跑过来看一下结果来了没有,没来的话,我又去忙别的,过了一会儿,我又来看结果来了没有,那么这时候我们可以看一下api文档,Future对象上有没有一种方法可以,我先去看有没有结果,如果没有结果,我就去忙别的,而不是必须在那里等。我们看到有一个get的重载方法V get(long timeout, TimeUnit unit),这个方法可以设定等待的时间。如果它是说超过等待的时间没有返回结果,我就可以去做别的事,这还比较好。如果超过时间没有结果就抛异常的话,这就受不了了。结果它是抛的一个Timeout异常。这就不行了,我的本意事没有就没有呗,没有我就去干别的事,结果呢,它非要去跟人家打一架,大的头破血流都报红了。这样,感觉就没有什么太大的意义。

CompletionService提交一组Callable任务,并获得它们的返回值

接下来我们再看一种应用CompletionService,就是我一下就提交一组Callable任务,然后我就用它的返回值类型CompletionService的take方法去取,凡是只要有一个任务运行完了,我就会得到结果。哪个任务先执行完,就先拿到哪个任务的结果。如果有10个任务,就要拿10次结果。它的泛型就是任务的返回值的类型。我们用CompletionService的子类ExecutorCompletionService来创建对象,这个创建的对象它不是一个线程池,它执行的时候,比如它有10个任务需要运行的时候,它是不是要交给线程池来执行呀。所以呢,我们还要给它的构造方法传入一个线程池对象。

ExecutorService threadPool2 = Executors.newFixedThreadPool(10);

        CompletionService<Integer> completionService = new ExecutorCompletionService<Integer>(threadPool2);

        for (int i = 1; i <= 10; i++) {

            final int seq = i;

            completionService.submit(new Callable<Integer>() {

                @Override

                public Integer call() throws Exception {

                    Thread.sleep(new Random().nextInt(5000));

                    return seq;

                }

            });

        }

        for (int i = 0; i < 10; i++) {

            try {

                System.out.println(completionService.take().get());

            } catch (InterruptedException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            } catch (ExecutionException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }

        }

猜你喜欢

转载自my.oschina.net/u/3512041/blog/1822032