InterruptedException, ExecutionException, TimeoutException;
提供了五个方法
public abstract boolean cancel(boolean paramBoolean)
试图取消任务的执行(注意是试图),因为存在一些任务已完成、已取消或者因为某些原因无法取消的因素,存在着取消失败的可能性。
当canel方法起作用时,有两个情况:
1.任务未开始,则该任务将永远不会运行;
2.任务处于执行状态,paramBoolean表示是否采用中断的方式中断线程。
public abstract boolean isCancelled()
如果任务正常取消的,则返回true。
public abstract boolean isDone();
如果任务已完成,则返回 true。 可能由于正常终止、异常或取消而完成,在所有这些情况中,此方法都将返回 true。
(注意如果调用isCanle方法,那么isDone将始终返回true).
public abstract V get() throws InterruptedException, ExecutionException;
重点到了!这是Future获取计算结果的方式之一,使用get方法。(注意这里返回的是Callable中的泛型)
get方法取决于任务的状态(未开始,运行中,已完成),如果任务已经完成,那么get会立即返回或者抛出一个异常;
如果任务没有完成,那么get将阻塞知道任务完成。如果任务抛出了异常,那么get会将该异常封装成ExecutionException抛出。
public abstract V get(long paramLong, TimeUnit paramTimeUnit)
throws InterruptedException, ExecutionException, TimeoutException;
如果需要在给定时间后获取计算结果,可以使用这个方法,如果超过给定时间之后没有得到计算结果,则抛出TimeoutException。(注意这里返回的是Callable中的泛型)
来看代码:
import java.util.concurrent.*;
public class Demo1 {
public static void main(String args[]) throws Exception {
// 1.先实例化任务对象
ServiceTask task = new ServiceTask();
// 2.实例化Executor框架中的线程池
ExecutorService executor = Executors.newCachedThreadPool();
// 3.使用submit方法将任务提交(返回的是一个Future)
Future<Integer> result = executor.submit(task);
// 4.记得关闭线程池
executor.shutdown();
System.out.println("正在执行任务");
Thread.sleep(1000);
// 5.打印最后的结果
System.out.println("task运行结果为:" + result.get());
* Callable的实现类
class ServiceTask implements Callable<Integer>{
@Override
public Integer call() throws Exception {
Thread.sleep(2000);
int result = 0;
// 假设一个很庞大的计算
for(int i=1;i<100;i++){
for (int j=0;j<i;j++){
result +=j;
return result;
运行结果:
接下来我们来试一下定时取结果:
还是在原来的代码上修改:
import java.util.concurrent.*;
public class Demo1 {
public static void main(String args[]) throws Exception {
// 1.先实例化任务对象
ServiceTask task = new ServiceTask();
// 2.实例化Executor框架中的线程池
ExecutorService executor = Executors.newCachedThreadPool();
// 3.使用submit方法将任务提交(返回的是一个Future)
Future<Integer> result = executor.submit(task);
// 4.记得关闭线程池
executor.shutdown();
System.out.println("正在执行任务");
Thread.sleep(1000);
// 5.设置定时一秒取结果
System.out.println("task运行结果为:" + result.get(1,TimeUnit.MILLISECONDS));
* Callable的实现类
class ServiceTask implements Callable<Integer>{
@Override
public Integer call() throws Exception {
//这里睡眠2秒
Thread.sleep(2000);
int result = 0;
// 假设一个很庞大的计算
for(int i=1;i<100;i++){
for (int j=0;j<i;j++){
result +=j;
return result;
来提前猜想一下,首先设置了定时一秒之后取得结果,但是ServiceTask设置两秒的睡眠时间,理应取结果失败,看一下运行结果:
是的,如果在规定时间内无法取到结果,就会返回TimeoutException。
谈谈FutureTask
FutureTask是Future的实现类,它继承了RunnableFuture,RunnableFuture实际上继承了Runnable和Future接口。
来看一下使用如何FutureTask:
import java.util.concurrent.*;
public class FutureCallDemo2 {
public static void main(String args[])throws Exception{
// 1.先实例化任务对象
FutureTaskService task = new FutureTaskService();
// 2.实例化Executor框架中的线程池
ExecutorService excutor = Executors.newCachedThreadPool();
// 3.直接new一个FutureTask
FutureTask<Long> result = new FutureTask<Long>(task);
// 4.提交任务
excutor.submit(result);
// 5.关闭线程池
excutor.shutdown();
System.out.println("主线程正在执行任务");
System.out.println("task运行结果为:" + result.get());
* 继承Callable接口
class FutureTaskService implements Callable<Long> {
@Override
public Long call() throws Exception {
Thread.sleep(3000);
// 10的阶乘
long sum = 1;
for (int i = 1; i <= 10; i++) {
sum = sum * i;
return sum;
用法的话其实差不多。
Future和Callable可以实现异构任务,但是有很多值得考虑的地方。
比如一个类使用了两个任务,一个负责渲染页面,一个负责下载图像。
伪代码如下:
//通过获取图像
List<ImageData>ImageDataList = future.get();
for(ImageData data:ImageDataList ){
//渲染页面
renderPage(data);
看似并行的执行任务,但是却存在着问题。如果说下载图像的速度远小于渲染页面的速度,那么最终的执行速度就和串行无异了。
所以只有当大量相互独立且同构的任务可以进行并发处理时,才能体现出将任务分到多个任务中带来的性能提升,考虑实际情况再选择使用会带来事半功倍的效果。
本文参考:
Java并发编程实战
个人博客网站 http://www.janti.cn