本章主要学习Future接口。
1.Future接口概述
Future接口代表着异步计算的结果。
Future接口提供了一些方法:查看计算是否完成、等待计算完成和获取计算结果。
只有在计算完成时,才能通过get()方法获取计算结果,必要时程序会阻塞直到计算完成。
取消计算是通过方法cancel()执行的。
此外,还提供了一些其他的方法用于确认任务是否正常(isDone())或者是否取消(isCancelled())。
一旦一个计算已经完成,则这个计算不能再被取消。
如果你因为可取消性而想使用Future接口,但是又不能提供一个可用的计算结果,那么你可以将其声明为Future<?>
类型,并且以null值作为返回值。
示例用法
interface ArchiveSearcher {
String search(String target);
}
class App {
ExecutorService executor = ...
ArchiveSearcher searcher = ...
void showSearch(final String target)
throws InterruptedException {
Future<String> future
= executor.submit(new Callable<String>() {
public String call() {
return searcher.search(target);
}
});
displayOtherThings(); // do other things while searching
try {
displayText(future.get()); // use future
} catch (ExecutionException ex) {
cleanup();
return;
}
}
}
谨记一致性影响:
一个线程池中异步计算的结果 happens-before 另一个线程中Future.get()方法之后的操作。
也就是说: 一个线程池中异步计算的结果 对 另一个线程中 Future.get()方法 之后的操作 可见。
2.Future的方法说明
Future的方法如下:
1.isDone():任务是否完成
2.isCancelled():任务是否取消了
3.cancel(mayInterruptIfRunning):
取消任务:
- mayInterruptIfRunning = true:如果任务在运行,则即使中断任务,也要取消任务。
- mayInterruptIfRunning = false:如果任务在运行,则等待任务运行完毕,再取消任务。
4.get():
阻塞的的获取计算结果,直到发生以下三种情况之一:
- 获取了计算结果,返回结果。
- 当前线程被中断被中断,抛出InterruptedException异常。
- 计算出错,则抛出ExecutionException异常。
5.get(timeout,TimeUnit):
在限定时间内,阻塞的的获取计算结果,直到发生以下四种情况之一:
- 获取了计算结果,则返回结果。
- 当前线程被中断被中断,则抛出InterruptedException异常
- 计算出错,则抛出ExecutionException异常。
- 等待时间超时,则抛出TimeoutException异常。
3.实例练习
练习目的:熟悉Future各方法的使用。
练习描述:
- isDone()和isCancelled()的使用
- cancel(true)的使用
- get(timeout,TimeUnit)的使用
- get()的使用
实例代码:
//定义一个线程池
ExecutorService executorService = Executors.newCachedThreadPool();
//定义一个Callable对象
Callable callable = new Callable() {
@Override
public Object call() throws Exception {
//模拟开始计算
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
//e.printStackTrace();
System.out.println("正在计算,被取消了");
}
//计算结束,返回结果
return 100;
}
};
//提交一个Callable任务,返回一个Future对象
Future<Integer> future = executorService.submit(callable);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//isDone():任务是否完成
System.out.println("1000ms的时候计算是否完成:" + future.isDone());
//isCancelled():任务是否取消了
System.out.println("1000ms的时候计算是否取消:" + future.isCancelled());
System.out.println();
//cancel取消-true表示即使在运行也取消,false表示如果没运行可以取消
future.cancel(true);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//isDone():任务是否完成
System.out.println("cancel之后计算是否完成:" + future.isDone());
//isCancelled():任务是否取消了
System.out.println("cancel之后计算是否取消:" + future.isCancelled());
System.out.println();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//再次提交一个Callable任务,返回一个Future对象
future = executorService.submit(callable);
//在2秒时限内尝试去获取
//获取到则返回结果
//获取不到则返回
try {
System.out.println("在2秒时限内尝试去获取:" + future.get(2, TimeUnit.SECONDS));
} catch (TimeoutException e) {
//e.printStackTrace();
System.out.println("timeout超时,抛出TimeoutException异常");
} catch (InterruptedException e) {
//e.printStackTrace();
System.out.println("线程interrupt,抛出InterruptedException异常");
} catch (ExecutionException e) {
//e.printStackTrace();
System.out.println("执行出错,抛出ExecutionException异常");
}
//isDone():任务是否完成
System.out.println("get(timeout,TimeUnit)超时之后,计算是否完成:" + future.isDone());
//isCancelled():任务是否取消了
System.out.println("get(timeout,TimeUnit)超时之后,cancel之后计算是否取消:" + future.isCancelled());
System.out.println();
//阻塞的等待计算结果,直到获取计算结果
try {
System.out.println("阻塞的等待计算结果,直到获取计算结果:" + future.get());
} catch (InterruptedException e) {
//e.printStackTrace();
System.out.println("线程interrupt,抛出InterruptedException异常");
} catch (ExecutionException e) {
//e.printStackTrace();
System.out.println("执行出错,抛出ExecutionException异常");
}
//isDone():任务是否完成
System.out.println("get()之后,计算是否完成:" + future.isDone());
//isCancelled():任务是否取消了
System.out.println("get()之后,cancel之后计算是否取消:" + future.isCancelled());
//取消线程池
executorService.shutdown();
运行结果:
1000ms的时候计算是否完成:false
1000ms的时候计算是否取消:false
正在计算,被取消了
cancel之后计算是否完成:true
cancel之后计算是否取消:true
timeout超时,抛出TimeoutException异常
get(timeout,TimeUnit)超时之后,计算是否完成:false
get(timeout,TimeUnit)超时之后,cancel之后计算是否取消:false
阻塞的等待计算结果,直到获取计算结果:100
get()之后,计算是否完成:true
get()之后,cancel之后计算是否取消:false