[转载] Java并发编程:Callable、Future和FutureTask
转载自http://www.cnblogs.com/dolphin0520/p/3949310.html
在前面的文章中我们讲述了创建线程的2种方式,一种是直接继承Thread,另外一种就是实现Runnable接口。
这2种方式都有一个缺陷就是:在执行完任务之后无法获取执行结果。
如果需要获取执行结果,就必须通过共享变量或者使用线程通信的方式来达到效果,这样使用起来就比较麻烦。
而自从Java 1.5开始,就提供了Callable和Future,通过它们可以在任务执行完毕之后得到任务执行结果。
今天我们就来讨论一下Callable、Future和FutureTask三个类的使用方法。以下是本文的目录大纲:
一.Callable与Runnable
二.Future
三.FutureTask
四.使用示例
若有不正之处请多多谅解,并欢迎批评指正。
请尊重作者劳动成果,转载请标明原文链接:
http://www.cnblogs.com/dolphin0520/p/3949310.html
一.Callable与Runnable
先说一下java.lang.Runnable吧,它是一个接口,在它里面只声明了一个run()方法:
| 
 1 
2 
3 
 | 
public interface Runnable {    public abstract void run();} | 
由于run()方法返回值为void类型,所以在执行完任务之后无法返回任何结果。
Callable位于java.util.concurrent包下,它也是一个接口,在它里面也只声明了一个方法,只不过这个方法叫做call():
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
 | 
public interface Callable<V> {    /**     * Computes a result, or throws an exception if unable to do so.     *     * @return computed result     * @throws Exception if unable to compute a result     */    V call() throws Exception;} | 
可以看到,这是一个泛型接口,call()函数返回的类型就是传递进来的V类型。
那么怎么使用Callable呢?一般情况下是配合ExecutorService来使用的,在ExecutorService接口中声明了若干个submit方法的重载版本:
| 
 1 
2 
3 
 | 
<T> Future<T> submit(Callable<T> task);<T> Future<T> submit(Runnable task, T result);Future<?> submit(Runnable task); | 
第一个submit方法里面的参数类型就是Callable。
暂时只需要知道Callable一般是和ExecutorService配合来使用的,具体的使用方法讲在后面讲述。
一般情况下我们使用第一个submit方法和第三个submit方法,第二个submit方法很少使用。
二.Future
Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果。必要时可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果。
Future类位于java.util.concurrent包下,它是一个接口:
| 
 1 
2 
3 
4 
5 
6 
7 
8 
 | 
public interface Future<V> {    boolean cancel(boolean mayInterruptIfRunning);    boolean isCancelled();    boolean isDone();    V get() throws InterruptedException, ExecutionException;    V get(long timeout, TimeUnit unit)        throws InterruptedException, ExecutionException, TimeoutException;} | 
在Future接口中声明了5个方法,下面依次解释每个方法的作用:
- cancel方法用来取消任务,如果取消任务成功则返回true,如果取消任务失败则返回false。参数mayInterruptIfRunning表示是否允许取消正在执行却没有执行完毕的任务,如果设置true,则表示可以取消正在执行过程中的任务。如果任务已经完成,则无论mayInterruptIfRunning为true还是false,此方法肯定返回false,即如果取消已经完成的任务会返回false;如果任务正在执行,若mayInterruptIfRunning设置为true,则返回true,若mayInterruptIfRunning设置为false,则返回false;如果任务还没有执行,则无论mayInterruptIfRunning为true还是false,肯定返回true。
 - isCancelled方法表示任务是否被取消成功,如果在任务正常完成前被取消成功,则返回 true。
 - isDone方法表示任务是否已经完成,若任务完成,则返回true;
 - get()方法用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回;
 - get(long timeout, TimeUnit unit)用来获取执行结果,如果在指定时间内,还没获取到结果,就直接返回null。
 
也就是说Future提供了三种功能:
1)判断任务是否完成;
2)能够中断任务;
3)能够获取任务执行结果。
因为Future只是一个接口,所以是无法直接用来创建对象使用的,因此就有了下面的FutureTask。
三.FutureTask
我们先来看一下FutureTask的实现:
| 
 1 
 | 
public class FutureTask<V> implements RunnableFuture<V> | 
FutureTask类实现了RunnableFuture接口,我们看一下RunnableFuture接口的实现:
| 
 1 
2 
3 
 | 
public interface RunnableFuture<V> extends Runnable, Future<V> {    void run();} | 
可以看出RunnableFuture继承了Runnable接口和Future接口,而FutureTask实现了RunnableFuture接口。所以它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值。
FutureTask提供了2个构造器:
| 
 1 
2 
3 
4 
 | 
public FutureTask(Callable<V> callable) {}public FutureTask(Runnable runnable, V result) {} | 
事实上,FutureTask是Future接口的一个唯一实现类。
四.使用示例
1.使用Callable+Future获取执行结果
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
 | 
public class Test {    public static void main(String[] args) {        ExecutorService executor = Executors.newCachedThreadPool();        Task task = new Task();        Future<Integer> result = executor.submit(task);        executor.shutdown();                 try {            Thread.sleep(1000);        } catch (InterruptedException e1) {            e1.printStackTrace();        }                 System.out.println("主线程在执行任务");                 try {            System.out.println("task运行结果"+result.get());        } catch (InterruptedException e) {            e.printStackTrace();        } catch (ExecutionException e) {            e.printStackTrace();        }                 System.out.println("所有任务执行完毕");    }}class Task implements Callable<Integer>{    @Override    public Integer call() throws Exception {        System.out.println("子线程在进行计算");        Thread.sleep(3000);        int sum = 0;        for(int i=0;i<100;i++)            sum += i;        return sum;    }} | 
执行结果:
2.使用Callable+FutureTask获取执行结果
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
44 
45 
 | 
public class Test {    public static void main(String[] args) {        //第一种方式        ExecutorService executor = Executors.newCachedThreadPool();        Task task = new Task();        FutureTask<Integer> futureTask = new FutureTask<Integer>(task);        executor.submit(futureTask);        executor.shutdown();                 //第二种方式,注意这种方式和第一种方式效果是类似的,只不过一个使用的是ExecutorService,一个使用的是Thread        /*Task task = new Task();        FutureTask<Integer> futureTask = new FutureTask<Integer>(task);        Thread thread = new Thread(futureTask);        thread.start();*/                 try {            Thread.sleep(1000);        } catch (InterruptedException e1) {            e1.printStackTrace();        }                 System.out.println("主线程在执行任务");                 try {            System.out.println("task运行结果"+futureTask.get());        } catch (InterruptedException e) {            e.printStackTrace();        } catch (ExecutionException e) {            e.printStackTrace();        }                 System.out.println("所有任务执行完毕");    }}class Task implements Callable<Integer>{    @Override    public Integer call() throws Exception {        System.out.println("子线程在进行计算");        Thread.sleep(3000);        int sum = 0;        for(int i=0;i<100;i++)            sum += i;        return sum;    }} | 
如果为了可取消性而使用 Future 但又不提供可用的结果,则可以声明 Future<?> 形式类型、并返回 null 作为底层任务的结果。
[转载] Java并发编程:Callable、Future和FutureTask的更多相关文章
- Java 并发编程——Callable+Future+FutureTask
		
Java 并发编程系列文章 Java 并发基础——线程安全性 Java 并发编程——Callable+Future+FutureTask java 并发编程——Thread 源码重新学习 java并发 ...
 - [转载]  java并发编程:Lock(线程锁)
		
作者:海子 原文链接: http://www.cnblogs.com/dolphin0520/p/3923167.html 出处:http://www.cnblogs.com/dolphin0520/ ...
 - [转载]Java并发编程:深入剖析ThreadLocal
		
原文地址:http://www.cnblogs.com/dolphin0520/p/3920407.html 想必很多朋友对ThreadLocal并不陌生,今天我们就来一起探讨 ...
 - [转载]Java并发编程:volatile关键字解析
		
Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在 ...
 - java 并发runable,callable,future,futureTask
		
转载自:http://www.cnblogs.com/dolphin0520/p/3949310.html package future_call; import java.util.concurre ...
 - 【原创】JAVA并发编程——Callable和Future源码初探
		
JAVA多线程实现方式主要有三种:继承Thread类.实现Runnable接口.使用ExecutorService.Callable.Future实现有返回结果的多线程.其中前两种方式线程执行完后都没 ...
 - java:并发编程-Callable与Future模式
		
自己对线程池的理解: coresize 3 maxsize 5 blockLinkedQuenue 3 当提交的任务在<=3时,创建三个线程干活 大于3时,把任务先加入阻塞式队列,当有空闲的核心 ...
 - 【并发编程】Future和FutureTask以及CompletionService
		
Future接口 此接口主要用于: 代表异步计算的执行结果: 用于可取消的task:(比使用interrupt实现取消要方便 ) FutureTask类 FutureTask是Future的一个实现类 ...
 - [转载] Java并发编程:Lock
		
转载自http://www.cnblogs.com/dolphin0520/p/3923167.html 以下是本文目录大纲: 一.synchronized的缺陷 二.java.util.concur ...
 
随机推荐
- Hadoop就是一个别人造好的轮子
			
这个想法源自于我看了<Hadoop: The Definitive Guide>的Part I Ch 2中MapReduce的引入和介绍,书中先说了怎么通过原始的办法处理数据,然后引入到如 ...
 - Python GUI - Tkinter tkMessageBox
			
Python GUI - Tkinter tkMessageBox: tkMessageBox模块用于显示在您的应用程序的消息框.此模块提供了一个功能,您可以用它来显示适当的消息 tkMess ...
 - 移动端效果之CellSwiper
			
写在前面 接着之前的移动端效果讲解,刚好项目中需要使用到这一效果,去饿了么的组件库看了一下效果,发现效果和微信端的cellSwiper还是有点差别的,由于项目中又是使用的React,之前使用的Reac ...
 - oracle基本查询语句总结
			
spool E:\基本查询.txt 将命令行的语句写入到指定的目下的指定的文件中 host cls 清屏命令 show user 显示当前操作的用户 desc emp 查看表结构 select * f ...
 - thinking in java 随笔
			
初始化顺序 在一个类里,初始化的顺序是由变量在类内的定义顺序决定的.即使变量定义大量遍布于方法定义的中间,那些变量仍会在调用任何方法之前得到初始化--甚至在构建器调用之前.例如: class Tag ...
 - 创建静态库Static Library(Framework库原理相似)
			
在项目开发的过程中,经常使用静态库文件.例如两个公司之间业务交流,不可能把源代码都发送给另一个公司,这时候将私密内容打包成静态库,别人只能调用接口,而不能知道其中实现的细节. 简介: 库是一些没有ma ...
 - 构造函数,This关键字
			
构造函数: 即构建创造对象时调用的函数.在new的时候自动执行,给对象进行初始化.创建对象都必须要通过构造函数初始化.(有参和无参) 一个类中如果没有定义过构造函数,那么类中会有一个默认的空参数构造函 ...
 - 使用phpExcel导出excel时,报500错
			
在自己本地导出excel没有问题,但是放到服务器出现500的错误! 解决方法:查看控制器引用的header文件,是否包含空格,如下: header('Pragma:public'); ...
 - STM32F10x -- 利用IIC协议操作AT24C02
			
关于AT24C02芯片的一些参数性能可参考其他的一些相关资料.此处只贴出程序. 宏文件AT24CXX.h #ifndef _AT24CXX_H_ #define _AT24CXX_H_ #includ ...
 - Java Stream
			
Stream 有两种类型的操作:Intermedidate操作和Terminal操作 Intermedidate(中间操作):Stream可以有多个Intermediate操作,Intermedida ...