[笔记][Java7并发编程实战手册]4.4 在执行器中执行任务并返回结果Callable、Future
来源:互联网 发布:铁血皇城轮回数据 编辑:程序博客网 时间:2024/05/18 20:12
[笔记][Java7并发编程实战手册]系列目录
简介
执行框架(Executor Framework)的优势之一就是,可以在运行并发任务的时候返回结果。但是需要以下两个类来实现功能:
1. 接口 Callable<V>
返回结果并且可能抛出异常的任务。实现者定义了一个不带任何参数的叫做 call 的方法。
Callable 接口类似于 Runnable,两者都是为那些其实例可能被另一个线程执行的类设计的。但是 Runnable 不会返回结果,并且无法抛出经过检查的异常。
Executors 类包含一些从其他普通形式转换成 Callable 类的实用方法。简单说:就是实现这个类,并在唯一的call() 方法里面实现自己的业务逻辑。
2.接口 Future<V>
Future 表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。计算完成后只能使用 get 方法来获取结果,如有必要,计算完成前可以阻塞此方法。取消则由 cancel 方法来执行。还提供了其他方法,以确定任务是正常完成还是被取消了。一旦计算完成,就不能再取消计算。如果为了可取消性而使用 Future 但又不提供可用的结果,则可以声明 Future
<?>
形式类型、并返回 null 作为底层任务的结果。简单说:该接口可以获取一个线程的结果。调用get的时候,如果结果没有计算完成,则阻塞。这个接口我觉得得好好理解下,在使用谷歌的AsyncHttpClient 异步的同步支持http Client的时候,里面就是使用 future来作为返回结果。利用它就能异步的请求和推送结果。
用谷歌的AsyncHttpClient简单模仿安卓的AsyncHttpClient,实现异步请求回调函数返回值
在本章将学习如何实现任务的返回结果,并在执行器中运行任务。
本章Callable和future使用心得
- Callable 和 Runnable类似,只不过Callable可以返回结果。
- Callable中的运行无论是否正常运行完成或则是抛出异常,在Future.get() 之前都不会抛出异常,并且Future.isDone() 都会返回ture
- ThreadPoolExecutor.getCompletedTaskCount() 是返回完成的任务数量,是指 Future.isDone() 为ture的数量。
4.简单一句话:只要把callable任务交给执行器执行,然后坐等结果就行了,在执行一些不需要阻塞的等待运行结果的场景费用适用。
最后是一个疑问: 在谷歌的AsyncHttpClient中,AsyncHttpClient.BoundRequestBuilder builder = http.preparePost(url);Future f = builder.execute(); 代码中,不调用Future.get() 任务内容就没有被执行,也就是说在调用get() 方法之前,并没有发送http请求出去。 有关这个疑问。我猜想很有可能是 没有使用类似执行器的线程池来运行的原因吧。具体的原因等有空去看源代码才知道了。 如果有知道的可以告诉我下。
示例
场景描述: 下面示例讲的是,使用Callable任务类task,里面执行的内容是,外面传递进来什么就返回什么,其中使用随眠来模拟运算时间。然后把创建好的callable交给执行器执行。获得future对象,然后用future.get() 来获取结果
/** * Created by zhuqiang on 2015/8/30 0030. */public class Client { public static void main(String[] args) throws ExecutionException, InterruptedException { ArrayList<Future<Integer>> list = new ArrayList<Future<Integer>>(); ThreadPoolExecutor ex = (ThreadPoolExecutor) Executors.newFixedThreadPool(3); for (int i = 0; i < 5; i++) { Task task = new Task(i); Future<Integer> f = ex.submit(task); //把callable的task交给线程来运行, list.add(f); //把future对象搜集起来。获取结果 } ex.shutdown(); // 通过isDone来获取任务的完成状况。isDone:如果任务已完成,则返回 true。 可能由于正常终止、异常或取消而完成,在所有这些情况中,此方法都将返回 true。 do { for (int i = 0; i < list.size(); i++) { Future<Integer> f = list.get(i); if(f.isDone()){ System.out.printf("Main_Task_%s任务是否完成:%s\n", i,true); } } TimeUnit.MILLISECONDS.sleep(500); //休眠500毫秒 }while (ex.getCompletedTaskCount() < list.size()); //当执行器中完成的任务数量 小于目标数量。则一直循环获取任务的完成情况 //所有任务都完成后,就打印出返回的结果 System.out.println("\n---------------------- Main 结果 --------------------------------\n"); for (int i = 0; i < list.size(); i++) { Future<Integer> f = list.get(i); System.out.printf("Main_Task_%s的结果是:%s\n", i, f.get()); //因为get() 方法如果线程还没有计算完成。则会阻塞直到返回结果。所以前面才没有直接使用get获取结果,而是获取执行器里面的任务完成状态,观察任务运行情况 } }}class Task implements Callable<Integer>{ public int num; public Task(int num) { this.num = num; } @Override public Integer call() throws Exception { long time = (long)(Math.random() * 10); TimeUnit.SECONDS.sleep(time);// if(1 == num){ // 其实:我想测试,在执行器中执行的时候,任务是否真的执行了,这点让我很迷茫。 因为在我做过的业务中:异步的发送http请求,使用future来发送。但是如果我不调用get() 的话,那么就没有被发送请求.然后在这里测试,没有调用get的时候的确执行了// throw new RuntimeException("测试抛出异常");// } System.out.printf("%s休眠了%s秒\n", Thread.currentThread().getName(), time); return num; }}
某一次的运行结果:
pool-1-thread-3休眠了3秒Main_Task_2任务是否完成:trueMain_Task_2任务是否完成:trueMain_Task_2任务是否完成:trueMain_Task_2任务是否完成:trueMain_Task_2任务是否完成:truepool-1-thread-1休眠了6秒pool-1-thread-2休眠了6秒Main_Task_0任务是否完成:trueMain_Task_1任务是否完成:trueMain_Task_2任务是否完成:truepool-1-thread-3休眠了3秒Main_Task_0任务是否完成:trueMain_Task_1任务是否完成:trueMain_Task_2任务是否完成:trueMain_Task_3任务是否完成:trueMain_Task_0任务是否完成:trueMain_Task_1任务是否完成:trueMain_Task_2任务是否完成:trueMain_Task_3任务是否完成:trueMain_Task_0任务是否完成:trueMain_Task_1任务是否完成:trueMain_Task_2任务是否完成:trueMain_Task_3任务是否完成:trueMain_Task_0任务是否完成:trueMain_Task_1任务是否完成:trueMain_Task_2任务是否完成:trueMain_Task_3任务是否完成:trueMain_Task_0任务是否完成:trueMain_Task_1任务是否完成:trueMain_Task_2任务是否完成:trueMain_Task_3任务是否完成:truepool-1-thread-1休眠了3秒---------------------- Main 结果 --------------------------------Main_Task_0的结果是:0Main_Task_1的结果是:1Main_Task_2的结果是:2Main_Task_3的结果是:3Main_Task_4的结果是:4
结果说明:
可以看到上面的运行结果,在我们把task交给执行器执行的时候,的确是以线程的方式在运行了。等待全部任务结束后,能获取到正确的返回结果。如果我们把上面的异常打开,就能看到 就算程序抛出了异常,但是在不调用get() 之前是不会抛出异常的。然后 任务完成状态却和jdk说明一致,是true
- [笔记][Java7并发编程实战手册]4.4 在执行器中执行任务并返回结果Callable、Future
- Java7并发编程--4.4、在执行器中执行任务并且返回结果
- [笔记][Java7并发编程实战手册]4.11-4.12在执行器中分离任务的启动和结果的处理和处理在执行器中被拒绝的任务
- [笔记][Java7并发编程实战手册]4.7-4.8 在执行器中延迟执行或则周期执行任务ScheduledThreadPoolExecutor
- Java7并发编程--4.2、在执行器中执行任务并且返回结果
- [笔记][Java7并发编程实战手册]4.9-4.10在执行器中控制任务的完成和取消任务FutureTask
- 并发编程--在执行器中执行任务并返回结果
- Java并发编程-17-在执行器中执行任务并返回结果
- [笔记][Java7并发编程实战手册]4.5-4.6 运行多个任务并处理第一个结果/所有结果ThreadPoolExecutor
- Java并发编程-18-在执行器中执行任务并处理结果
- JAVA 并发编程-返回执行结果(Callable和Future)(九)
- JAVA 并发编程-返回执行结果(Callable和Future)(九)
- [笔记][Java7并发编程实战手册]4.2 创建线程执行器newCachedThreadPool无界线程池
- [笔记][Java7并发编程实战手册]4.3 创建固定的线程执行器newFixedThreadPool线程池
- 执行器中执行任务并返回结果
- Java并发-执行器Callable,Future
- Callable和Future实现调用任务并返回结果数据
- Callable和Future实现调用任务并返回结果数据
- CodeForces #318 (div1) B.Bear and Blocks
- 程序员的浮躁症
- [Apache Software] - Apache Maven
- 排序算法
- linux 线程总结
- [笔记][Java7并发编程实战手册]4.4 在执行器中执行任务并返回结果Callable、Future
- poj 3278 Catch That Cow(经典bfs)
- ftok () 函数介绍
- 动态规划之合唱队形问题(最长递增子序列变形)
- 队列 的理解
- 再次写给我们这些浮躁的程序员
- 多方法实现 swap 2 个 int 变量的值
- 51nod 1264 线段相交(判线段相交 包括端点和部分重合)
- linux 线程 进程经典文章