Executors Future Callable 使用场景实例
https://www.jb51.net/article/132606.htm:
我们都知道实现多线程有2种方式,一种是继承Thread,一种是实现Runnable,但这2种方式都有一个缺陷,在任务完成后无法获取返回结果。要想获得返回结果,就得使用Callable,Callable任务可以有返回值,但是没法直接从Callable任务里获取返回值;想要获取Callabel任务的返回值,需要用到Future。所以Callable任务和Future模式,通常结合起来使用。
试想一个场景:需要一个帖子列表接口,除了需要返回帖子列表之外,还需要返回每条帖子的点赞列表和评论列表。一页10条帖子来计算,这个接口需要访问21次数据库,访问一次数据库按100ms计算,21次,累计时间为2.1s。这个响应时间,怕是无法令人满意的。怎么办呢?异步化改造接口。
查出帖子列表后,迭代帖子列表,在循环里起10个线程,并发去获取每条帖子的点赞列表,同时另起10个线程,并发去获取每条帖子的评论列表。这样改造之后,接口的响应时间大大缩短,在200ms。这个时候就要用Callabel结合Future来实现。
- private List<PostResponse> createPostResponseList(Page<PostResponse> page,final String userId){
- if(page.getCount()==0||page==null||page.getList()==null){
- return null;
- }
- //获取帖子列表
- List<PostResponse> circleResponseList = page.getList();
- int size=circleResponseList.size();
- ExecutorService commentPool = Executors.newFixedThreadPool(size);
- ExecutorService supportPool = Executors.newFixedThreadPool(size);
- try {
- List<Future> commentFutureList = new ArrayList<Future>(size);
- if (circleResponseList != null && circleResponseList.size() > 0) {
- for (PostResponse postResponse : circleResponseList) {
- final String circleId=postResponse.getId();
- final String postUserId=postResponse.getUserId();
- //查评论列表
- Callable<List<CircleReviews>> callableComment = new Callable<List<CircleReviews>>() {
- @Override
- public List<CircleReviews> call() throws Exception {
- return circleReviewsBiz.getPostComments(circleId);
- }
- };
- Future f = commentPool.submit(callableComment);
- commentFutureList.add(f);
- //查点赞列表
- Callable<List<CircleZan>> callableSupport = new Callable<List<CircleZan>>() {
- @Override
- public List<CircleZan> call() throws Exception {
- return circleZanBiz.findList(circleId);
- }
- };
- Future supportFuture = supportPool.submit(callableSupport);
- commentFutureList.add(supportFuture);
- }
- }
- // 获取所有并发任务的执行结果
- int i = 0;
- PostResponse temp = null;
- for (Future f : commentFutureList) {
- temp = circleResponseList.get(i);
- temp.setCommentList((List<CircleReviews>) f.get();
- temp.setSupportList((List<CircleZan>) f.get();
- circleResponseList.set(i, temp);
- i++;
- }
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- // 关闭线程池
- commentPool.shutdown();
- supportPool.shutdown();
- }
- return circleResponseList;
- }
★ 下面给出一个Executor执行Callable任务的示例代码(https://blog.csdn.net/ns_code/article/details/17465497?utm_source=blogxgwz0):
- import java.util.ArrayList;
- import java.util.List;
- import java.util.concurrent.*;
- public class CallableDemo{
- public static void main(String[] args){
- ExecutorService executorService = Executors.newCachedThreadPool();
- List<Future<String>> resultList = new ArrayList<Future<String>>();
- //创建10个任务并执行
- for (int i = 0; i < 10; i++){
- //使用ExecutorService执行Callable类型的任务,并将结果保存在future变量中
- Future<String> future = executorService.submit(new TaskWithResult(i));
- //将任务执行结果存储到List中
- resultList.add(future);
- }
- //遍历任务的结果
- for (Future<String> fs : resultList){
- try{
- while(!fs.isDone);//Future返回如果没有完成,则一直循环等待,直到Future返回完成
- System.out.println(fs.get()); //打印各个线程(任务)执行的结果
- }catch(InterruptedException e){
- e.printStackTrace();
- }catch(ExecutionException e){
- e.printStackTrace();
- }finally{
- //启动一次顺序关闭,执行以前提交的任务,但不接受新任务
- executorService.shutdown();
- }
- }
- }
- }
- class TaskWithResult implements Callable<String>{
- private int id;
- public TaskWithResult(int id){
- this.id = id;
- }
- /**
- * 任务的具体过程,一旦任务传给ExecutorService的submit方法,
- * 则该方法自动在一个线程上执行
- */
- public String call() throws Exception {
- System.out.println("call()方法被自动调用!!! " + Thread.currentThread().getName());
- //该返回结果将被Future的get方法得到
- return "call()方法被自动调用,任务返回的结果是:" + id + " " + Thread.currentThread().getName();
- }
- }
某次执行结果如下:
从结果中可以同样可以看出,submit也是首先选择空闲线程来执行任务,如果没有,才会创建新的线程来执行任务。另外,需要注意:如果Future的返回尚未完成,则get()方法会阻塞等待,直到Future完成返回,可以通过调用isDone()方法判断Future是否完成了返回。
Executors Future Callable 使用场景实例的更多相关文章
- Java多线程之Executor、ExecutorService、Executors、Callable、Future与FutureTask
1. 引子 初学Java多线程,常使用Thread与Runnable创建.启动线程.如下例: Thread t1 = new Thread(new Runnable() { @Override pub ...
- JVM源码分析-类加载场景实例分析
A类调用B类的静态方法,除了加载B类,但是B类的一个未被调用的方法间接使用到的C类却也被加载了,这个有意思的场景来自一个提问:方法中使用的类型为何在未调用时尝试加载?. 场景如下: public cl ...
- Linux 下 svn 场景实例及常用命令详解
一.SVN使用场景实例 问题: 在使用svn做为版本控制系统的软件开发中,经常会有这样的需求:在工作复本目录树的不同目录中增加了很多文件,但未纳入版本控制系统,这时如果使用svn add命令一个一个的 ...
- Java并发编程 - Executor,Executors,ExecutorService, CompletionServie,Future,Callable
一.Exectuor框架简介 Java从1.5版本开始,为简化多线程并发编程,引入全新的并发编程包:java.util.concurrent及其并发编程框架(Executor框架). Executor ...
- Java 多线程并发 Future+callable 实例
需求:一个业务实现 查询, 因为 要查询十几次, 所以每个平均0.6秒, 之前只有主线程一步步查 ,结果用了10秒,效率十分低下 , 于是改用线程池并发: 以下是代码设计: 1.线程池工具类: pac ...
- java 多线程 Future callable
面向对象5大设计原则 1.单一职责原则 一个类只包含它相关的方法,增删改查.一个方法只包含单一的功能,增加.一个类最多包含10个方法,一个方法最多50行,一个类最多500行.重复的代码进行封装,Do ...
- 并发编程-Future+callable+FutureTask 闭锁机制
项目中经常有些任务需要异步(提交到线程池中)去执行,而主线程往往需要知道异步执行产生的结果,这时我们要怎么做呢?用runnable是无法实现的,我们需要用callable实现. FutureTask ...
- 多线程常用代码 Future Callable Runable
public class ThreadPoolTest { public static void main(String[] args) throws InterruptedException { E ...
- Future Callable 线程池 例1
package com.niewj.concurrent; import java.util.concurrent.Callable; import java.util.concurrent.Exec ...
随机推荐
- Myeclipse2016安装Aptana
Myeclipse2016安装Aptana 想装个Aptana,装了半天,网上说的什么links方式啊,在线方式啊,都是什么的浮云. 所以自己来写个安装教程. 一.Aptana简要介绍 Aptana有 ...
- Linux中查看各文件夹大小(扫盘)
df -h ./ du -hs ./ du -h /ifs4/BC_RD/USER/lizhixin/my_project/human_chr22 | grep [[:digit:]+]G du [- ...
- android--------阿里 AndFix 热修复
AndFix,全称是Android hot-fix.是阿里开源的一个热补丁框架,允许APP在不重新发布版本的情况下修复线上的bug. 支持Android 2.3 到 6.0,并且支持arm 与 X86 ...
- 使用Laravel提交POST请求出现The page has expired due to inactivity错误
任何指向 web 中 POST, PUT 或 DELETE 路由的 HTML 表单请求都应该包含一个 CSRF 令牌(CSRF token),否则,这个请求将会被拒绝.
- Python基础--数据类型
一.数据类型是什么鬼? 计算机顾名思义就是可以做数学计算的机器,因此,计算机程序理所当然地可以处理各种数值.但是,计算机能处理的远不止数值,还可以处理文本.图形.音频.视频.网页等各种各样的数据,不同 ...
- spring boot 基础篇 -- 自带图片服务器
我们平时在日常项目中经常会遇到图片的上传和访问的情景,平时我们可能习惯于把图片传到resource或者项项目中的某个位置,这样会有一个缺点,当我们重新项目打包时,这些图片会丢失.为了解决这一缺点,我们 ...
- c++中的引用详解
什么是引用? 引用是C++语言的一个特殊的数据类型描述,用于在程序的不同的部分使用两个以上的变量名指向同一块地址,使得对其中任何一个变量的操作实际上都是对同一地址单元进行的. 使用时的注意事项: 引用 ...
- Oracle11g温习-第十章:存储架构
2013年4月27日 星期六 10:38 1.oracle 存储架构: 1) database ------------tablespace-------------segment(对象) --- ...
- OC self注意事项
#import <Foundation/Foundation.h> @interface Person : NSObject - (void)test; + (void)test; - ( ...
- 获取当前目录getcwd,设置工作目录chdir,获取目录信息
#include <unistd.h> #include <stdio.h> #include <limits.h> int main(int argc, char ...