Java多线程:Future和FutureTask
一、Future
Future是一个接口,所有方法如下:
上源码:
package java.util.concurrent;
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;
}
- cancel:取消任务(mayInterruptIfRunning是否中断正在执行的任务)。
- isCancelled:任务是否取消
- isDone:任务是否执行完成。
- get:获取任务结果
- get(long timeout, TimeUnit unit):有等待时间的获取任务结果。
二、FutureTask
FutureTask是一个类,实现了RunnableFuture
接口,RunnableFuture
接口继承了Runnable
和Future
,关系图如下:
FutureTask有两个构造函数:
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
第一个构造函数传入一个Callable
对象,第二个构造函数传入Runnable
对象和一个V
类型的对象,然后在函数中将这两个参数构造成一个Callable
对象。可见FutureTask
和Future
的核心就是要执行Callable
并获取返回结果。
FutureTask中的几种状态:
/**
*
* 可能的状态转换:
* NEW -> COMPLETING -> NORMAL
* NEW -> COMPLETING -> EXCEPTIONAL
* NEW -> CANCELLED
* NEW -> INTERRUPTING -> INTERRUPTED
*/
private volatile int state;
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
,运行时仅在set、setException和cancel方法中会转换为终端状态。终端状态共四种:NORMAL
结果正常、EXCEPTIONAL
结果异常、CANCELLED
任务取消、INTERRUPTED
任务中断,可能的状态转换源码中注释已写清楚。
三、示例
Future在线程池中主要做为一个返回(submit
方法),用于接收执行完成的结果,FutureTask则是具体实现。
测试代码:
public class ExecutorTest1 {
public static void main(String[] args) {
ExecutorService executorService = Executors.newSingleThreadExecutor();
ExecutorTest1 test1 = new ExecutorTest1();
Future<String> futureTest = executorService.submit(() -> test1.say("测试返回值"));
executorService.shutdown();
}
public String say(String a){
System.out.println("执行了say方法");
return "test"+a;
}
}
以上代码,执行了say方法,获取到了futureTest对象,但是futureTest对象不能直接使用,需要调用get方法获取结果,以上代码执行结果:
获取Future对象结果代码示例:
public class ExecutorTest1 {
public static void main(String[] args) {
ExecutorService executorService = Executors.newSingleThreadExecutor();
ExecutorTest1 test1 = new ExecutorTest1();
Future<String> futureTest = executorService.submit(() -> test1.say("测试返回值"));
try {
String s = futureTest.get();
System.out.println(s);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
executorService.shutdown();
}
public String say(String a){
System.out.println("执行了say方法");
return "test"+a;
}
}
可见要执行有返回值的线程,需要用Future来接收。那么FutureTask在哪里使用了呢,在执行方法的时候将传入的Callable对象或者Runnable对象封装成FutureTask对象,源码如下:
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
public <T> Future<T> submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
newTaskFor方法如下:
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
return new FutureTask<T>(runnable, value);
}
四、结果
Future和FutureTask的核心作用是获取有返回值的线程结果。