继承结构
FutureTask同时实现了Runnable接口和Future接口,因此可以直接提交给线程池执行,同时也可以返回线程的执行的结果
任务运行状态
private static final int NEW = 0;
private static final int COMPLETING = 1;
private static final int NORMAL = 2;
private static final int EXCEPTIONAL = 3;
private static final int CANCELLED = 4;
private static final int INTERRUPTING = 5;
private static final int INTERRUPTED = 6;
- NEW:表示是个新的任务或者还没被执行完的任务。这是初始状态。
- COMPLETING:任务已经执行完成或者执行任务的时候发生异常,但是任务执行结果或者异常原因还没有保存到outcome字段(outcome字段用来保存任务执行结果,如果发生异常,则用来保存异常原因)的时候,状态会从NEW变更到COMPLETING。但是这个状态会时间会比较短,属于中间状态。
- NORMAL:任务已经执行完成并且任务执行结果已经保存到outcome字段,状态会从COMPLETING转换到NORMAL。这是一个最终态。
- EXCEPTIONAL:任务执行发生异常并且异常原因已经保存到outcome字段中后,状态会从COMPLETING转换到EXCEPTIONAL。这是一个最终态。
- CANCELLED:任务还没开始执行或者已经开始执行但是还没有执行完成的时候,用户调用了cancel(false)方法取消任务且不中断任务执行线程,这个时候状态会从NEW转化为CANCELLED状态。这是一个最终态。
- INTERRUPTING: 任务还没开始执行或者已经执行但是还没有执行完成的时候,用户调用了cancel(true)方法取消任务并且要中断任务执行线程但是还没有中断任务执行线程之前,状态会从NEW转化为INTERRUPTING。这是一个中间状态。
- INTERRUPTED:调用interrupt()中断任务执行线程之后状态会从INTERRUPTING转换到INTERRUPTED。这是一个最终态。
状态的流转
get/cancle
FutrueTask是基于AQS实现的
FutureTask使用
A线程调用了B线程的FutureTask.run()方法,则A线程会等待B线程执行完之后才会继续执行
1.多个线程同时执行同一任务,每个任务只能执行一次
2.其它线程要等待这个任务执行完了才能继续执行
public class FutureTaskTest {
private final ConcurrentHashMap<Object, Future<String>> taskCache = new ConcurrentHashMap<>();
private String executeTask(final String taskName) throws ExecutionException, InterruptedException {
while (true) {
Future<String> future = taskCache.get(taskName);
if (future == null) {
Callable<String> callable = () -> {
Thread.sleep(1000);
return taskName;
};
FutureTask<String> futureTask = new FutureTask<>(callable);
//使用ConcurrentHashMap保证并发安全
future = taskCache.putIfAbsent(taskName,futureTask);
//保证同名的任务只会被执行一次
if(future == null){
future = futureTask;
futureTask.run();
}
}
try {
return future.get();
}catch (CancellationException e){
taskCache.remove(taskName, future);
}
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTaskTest futureTaskTest = new FutureTaskTest();
System.out.println(Thread.currentThread().getName() + futureTaskTest.executeTask("abc"));
System.out.println("等待任务执行完毕");
}
}
执行结果如下
主线程调用了FutrueTask的run()方法,主线程等待FutrueTask方法执行完了之后才会继续往下执行