关于 ExecutorService 和 Future 的中心思想

206 阅读2分钟

最近发现关于 ExecutorService 的理解容易错误,会只是把它当成多线程的思想来理解,但这样的理解其实是不对的很片面的,所以简单讲讲我的个人理解。

private ExecutorService executorService=null;
if (executorService == null) {
            executorService = Executors.newCachedThreadPool();//这里创建一个线程池
}
//提交任务
Future<String> future = executorService.submit(new Callable<String>() {

                @Override
                public String call() throws Exception {
                    // TODO: 2021/3/27  
                    Thread.sleep(10000);
                    return "result";
                }
 });
 ......
 //阻塞获取结果
 String result=future.get();
 
 //任务集合调用
 List<Callable<String>> all = new ArrayList<>();
 ....添加任务
 List<Future<String>> fs = executorService.invokeAll(all);//这里要稍微注意下,这个是阻塞的,看源码就知道List<Future<String>>已经是所有任务完成后的结果集了,没有单个执行灵活。

使用很简单,我们可以看到,显示创建了一个线程池,然后提交任务返回一个任务凭证 Future,当你需要用到结果的时候再去阻塞 get () 使用,所以整个的实现关键一个是线程池,一个是 Future;线程池其实你自己 new 一个 Thread 也就有了,Future 反而是关键。 所以这里的中心思想是【期货】, Future 这里可以理解为未完成的货物或功能,也就是期货中的票据,线程池就是期货公司。整个过程是这样的:

  1. 你去期货公司买期货,于是期货公司派了一个对接人(也就是线程)来跟你对接。
  2. 你说我要买一吨苹果,那期货公司肯定没有现成的,于是给你开了个单子(也就是 Future)
  3. 期货公司有了货之后改变订单状态(这里不是订阅通知的模型,只是改变 Future 的状态,因为订阅通知需要你设置回调对象的,这样就没办法做到异步执行同步调用了)
  4. 或者你实在急用(主线程执行要快),那你直接就睡到期货公司等着(阻塞的 get),取到货后一个订单就完成了。
  5. 当然你还可以同时买一吨苹果一吨梨一吨桔子,这样你就有了个三个单子,三个人给你办事(当然期货公司也可以就一个人,也就是线程池只有一个线程)。
  6. 整个交易的时间就是三个人中办事最慢的那个的时间。

所以不要理解错因果关系,是因为要实现期货这个模型需要多线程,并不是有了多线程它就是期货。