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

前两篇学习了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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值