Java多线程之Callable和Future
callable出现的原因:
创建线程的2种方式,一种是直接继承Thread,另外一种就是实现Runnable接口。这2种方式都有一个缺陷就是:在执行完任务之后无法获取执行结果。
如果需要获取执行结果,就必须通过共享变量或者使用线程通信的方式来达到效果,这样使用起来就比较麻烦。
Callable接口类似于Runnable,从名字就可以看出来了,但是Runnable不会返回结果,并且无法抛出返回结果的异常,而Callable功能更强大一些,被线程执行后,可以返回值,这个返回值可以被Future拿到,也就是说,Future可以拿到异步执行任务的返回值。
Callable接口提供了一个call()方法作为可以执行的线程体,但是call()方法比run()方法更强大。
- call()方法有返回值
- call()方法可以抛出异常
因此完全可以提供一个Callable对象作为Thread的target,而该线程的线程执行体就是该callable对象的call方法。问题是 :Callable接口是Java 5新增的接口,而且他不是Runnable接口的子接口,所以Callable对象不能直接作为Thread的target。而且call方法他有一个返回值————call方法并不是直接调用,它是作为线程的执行体被调用。哪吗如何获得call接口的返回值呢?
Java5提供了Future接口来代表Callable接口里的call方法的返回值,并为Future接口提供了一个Future提供了一个FutureTask实现类,该类实现了Future接口和Runable接口——可以作为Thread的target。
- boolean cancel(boolean mayInterruptIfRunning)
-
- 试图取消对此任务的执行。如果任务已完成、或已取消,或者由于某些其他原因而无法取消,则此尝试将失败。当调用 cancel 时,如果调用成功,而此任务尚未启动,则此任务将永不运行。如果任务已经启动,则 mayInterruptIfRunning 参数确定是否应该以试图停止任务的方式来中断执行此任务的线程。
-
- 此方法返回后,对 isDone() 的后续调用将始终返回 true。如果此方法返回 true,则对 isCancelled() 的后续调用将始终返回 true。
-
- 参数:mayInterruptIfRunning - 如果应该中断执行此任务的线程,则为 true;否则允许正在运行的任务运行完成
-
- 返回:如果无法取消任务,则返回 false,这通常是由于它已经正常完成;否则返回 true
boolean isCancelled()如果在任务正常完成前将其取消,则返回 true。
-
- 返回:如果任务完成前将其取消,则返回 true
boolean isDone()如果任务已完成,则返回 true。 可能由于正常终止、异常或取消而完成,在所有这些情况中,此方法都将返回 true。
-
- 返回:如果任务已完成,则返回 true
V get()
throws InterruptedException,
ExecutionException如有必要,等待计算完成,然后获取其结果。-
- 返回:计算的结果
-
- 抛出:
CancellationException - 如果计算被取消
ExecutionException - 如果计算抛出异常
InterruptedException - 如果当前的线程在等待时被中断
- 抛出:
V get(long timeout,
TimeUnit unit)
throws InterruptedException,
ExecutionException,
TimeoutException如有必要,最多等待为使计算完成所给定的时间之后,获取其结果(如果结果可用)。-
- 参数:
timeout - 等待的最大时间
unit - timeout 参数的时间单位
- 参数:
-
- 返回:计算的结果
-
- 抛出:
CancellationException - 如果计算被取消
ExecutionException - 如果计算抛出异常
InterruptedException - 如果当前的线程在等待时被中断
TimeoutException - 如果等待超时
- 抛出:
下面来看一个简单的例子:
public class CallableAndFuture {
public static void main(String[] args) {
Callable<Integer> callable = new Callable<Integer>() {
public Integer call() throws Exception {
return new Random().nextInt(100);
}
};
FutureTask<Integer> future = new FutureTask<Integer>(callable);
new Thread(future).start();
try {
Thread.sleep(5000);// 可能做一些事情
System.out.println(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}