多线程基础学习三:有返回值的线程类Callable

来源:互联网 发布:过山车是谁发明的 知乎 编辑:程序博客网 时间:2024/05/22 03:50

前两篇学习了Thread和Runnable的基础知识,学习另外一个多线成类Callable。

我在项目中遇到过这种场景,页面需要显示机票信息,时间分别为今天、明天,默认显示今天的,但是客户可能会看明天,要求点击明天不能给人明显的等待和迟滞的效果,然而查询机票需要调用第三方接口,接口每次只能查询一个时间的,并且查询时间比较长,大概20秒的样子。为了解决这个问题,要求页面调用接口的时候,要把下一天的的机票信息也查出来,如果在项目连续调用两次第三方接口,耗时就比较长,所以要开多线程,此时问题出来了,我了解到的多线程是没有返回数据的(当时还不知道有Callable这个接口)。
为了解决这个问题就需要使用Callable这个接口。

Callable基本信息

Callable在java.util.concurrent这个包中,而Thread和Runnable则在java.lang包中。
Callable适用在需要数据分批处理并且处理结果需要使用的场景,而Thread和Runnable的结果不影响主线程的执行。
Callable和Runable类似,实例都需要实现一个方法,都需要另外一个线程执行。

Callable的返回值依赖Future类,
Future类的说明:

A  Future represents the result of an asynchronous  computation.  Methods are provided to check if the computation is  complete, to wait for its completion, and to retrieve the result of  the computation.  The result can only be retrieved using method   get when the computation has completed, blocking if  necessary until it is ready.  Cancellation is performed by the   cancel method.  Additional methods are provided to  determine if the task completed normally or was cancelled. Once a  computation has completed, the computation cannot be cancelled.  If you would like to use a  Future for the sake  of cancellability but not provide a usable result, you can  declare types of the form  Future<?> and  return  null as a result of the underlying task.

中文翻译(自己翻译的,不保证百分百正确):

Future类代表了一个异步计算的结果,提供了检查是否计算完毕、等待执行完成、获取计算结果等方法。计算结果只能在计算完成时,通过get方法获取,如果没有计算完成调用get方法后就会调用方法的线程就会堵塞到异步线程计算完成为止。取消线程可以通过cancle方法。提供了额外的方法判断线程是计算完成了还是取消。一旦一个异步线程计算完成,计算就不能取消。如果是为了可以取消而不是获取一个有用的计算结果而是用Future类,你可以声明这种类型的Future(Future

Callable的使用

第一种用法:

public class CallableTest {    public static void main (String[] args) {        ExecutorService executorService = Executors.newCachedThreadPool();        CompletionService<String> completionService = new ExecutorCompletionService<String>(executorService);        int size = 0;        for (int i = 0; i < 5; i++) {            completionService.submit(new Test("Thread-" + i));            size++;        }        try {            while (size > 0) {                Future<String> future = completionService.take();                System.out.println(future.get());                size--;            }        } catch (Exception e) {            e.printStackTrace();        }    }    static class Test implements Callable<String> {        private String name;        public Test (String name) {            this.name = name;        }        @Override        public String call () throws Exception {            return name;        }    }}

这是看到最多的用法,把数据分成几个线程处理,然后逐一获取处理结果。
网上百度,发现还有其它用法。
第二种用法:

public class CallableSecond {    public static void main (String[] args) {        ExecutorService executorService = Executors.newCachedThreadPool();        Future<String> future = executorService.submit(new SecondTest());        try {            //SleepUtil.sleep(5000);            System.out.println(future.get());            System.out.println("主线程结束");        } catch (Exception e) {            e.printStackTrace();        }    }    static class SecondTest implements Callable<String> {        @Override        public String call () throws Exception {            SleepUtil.sleep(3000);            System.out.println("等待3秒");            return Thread.currentThread().getName();        }    }}

执行结果:

等待3秒pool-1-thread-1主线程结束

可以看到确实阻塞了线程,只有异步线程执行完了,才执行main的输出。
这种写法基本没有用过,没碰到过这种使用场景。

第三种写法:

public class CallThird {    public static void main (String[] args) {        FutureTask<String> task = new FutureTask<String>(new ThirdTest());        Thread thread = new Thread(task);        thread.start();        try {            System.out.println(task.get());            System.out.println("执行结束");        } catch (Exception e) {            e.printStackTrace();        }    }    static class ThirdTest implements Callable<String> {        @Override        public String call () throws Exception {            SleepUtil.sleep(3000);            System.out.println("等待了三秒");            return Thread.currentThread().getName();        }    }}

执行结果:

等待了三秒Thread-0执行结束

总结

三种写法都试了一下,目前用的比较多的还是第一种写法。

阅读全文
0 0