本文将会讲解Future类的主要方法和用法。
Future类
运作流程
在图中,右侧是一个线程池,线程池中有一些线程来执行任务。在图的左侧有一个 submit 方法,该方法往线程池中提交了一个 Task,这个 Task 实现了 Callable 接口,调用 submit 方法会立刻返回一个 Future 类型的对象,这个对象目前内容是空的,因为此时计算还没有完成。当计算一旦完成时,线程池便会把这个结果填入到之前返回的Future中去,这时就可以利用 Future 的 get 方法来获取到任务的执行结果了。
方法和用法
Future 接口的代码,一共有 5 个方法
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
}
get()
get方法在执行时的行为取决于Callable任务的状态,可能会发生以下 5 种情况:
- 任务已经执行完毕了,可以立刻返回,获取到任务执行的结果。
- 任务还没有结果(未开始或在执行中),去调用get的时候,都会把当前的线程阻塞,直到任务完成再把结果返回。
- 任务执行过程中抛出异常,调用get的时候,就会抛出ExecutionException 异常。
- 任务被取消了则会抛出 CancellationException。
- 调用了这个带延迟参数的get方法之后,如果call方法在规定时间内正常顺利完成了任务,那么get会正常返回;但是如果到达了指定时间依然没有完成任务,get 方法则会抛出 TimeoutException,代表超时了。
isDone()
这个方法如果返回 true 则代表执行完成了,并非一定是成功执行,抛出异常也会返回true;如果返回 false 则代表还没完成。
public class GetException {
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(20);
Future<Integer> future = service.submit(new CallableTask());
try {
for (int i = 0; i < 5; i++) {
System.out.println(i);
Thread.sleep(500);
}
System.out.println(future.isDone());
future.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
static class CallableTask implements Callable<Integer> {
@Override
public Integer call() throws Exception {
throw new IllegalArgumentException("Callable抛出异常");
}
}
}
0
1
2
3
4
true
java.util.concurrent.ExecutionException: java.lang.IllegalArgumentException: Callable抛出异常
//对于get而言,抛出的异常仍然时ExecutionException
cancel()
使用cancel
方法会有三种情况出现:
- 当任务还没有开始执行时,一旦调用 cancel,这个任务就会被正常取消,那么 cancel 方法返回 true。
- 如果任务已经完成,或者之前已经被取消过了,那么执行 cancel 方法则代表取消失败,返回 false。
- 这个任务正在执行,这个时候执行 cancel 方法是不会直接取消这个任务的,而是会根据我们传入的参数做判断。cancel 方法是必须传入一个参数,该参数叫作 mayInterruptIfRunning,如果值是 true,执行任务的线程就会收到一个中断的信号。如果传入的是 false 则就代表不中断正在运行的任务,也就是说,本次 cancel 不会有任何效果,同时 cancel 方法会返回 false。
isCancelled()
判断是否被取消,它和 cancel 方法配合使用
FutureTask的使用
典型用法是,把 Callable
实例当作 FutureTask
构造函数的参数,生成 FutureTask 的对象,然后把这个对象当作一个 Runnable
对象,放到线程池中或另起线程去执行,最后还可以通过 FutureTask 获取任务执行的结果。
/**
* 描述: 演示 FutureTask 的用法
*/
public class FutureTaskDemo {
public static void main(String[] args) {
Task task = new Task();
FutureTask<Integer> integerFutureTask = new FutureTask<>(task);
new Thread(integerFutureTask).start();
try {
System.out.println("task运行结果:"+integerFutureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
class Task implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("子线程正在计算");
int sum = 0;
for (int i = 0; i < 100; i++) {
sum += i;
}
return sum;
}
}