1. 使用
public static void testTaskFuture() throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newSingleThreadExecutor();
FutureTask<String> futureTask = new FutureTask<>(() -> {
log.info("开始执行任务.....");
TimeUnit.SECONDS.sleep(1);
String ans = "hello world";
log.info("执行任务完毕, 返回结果 : {}", ans);
return ans;
});
executorService.execute(futureTask);
for (int i = 0; i < 4; i++) {
new Thread(()->{
try {
String res = futureTask.get();
log.info("拿到执行结果 : {}", res);
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}).start();
}
//00:31:49.690 [pool-1-thread-1] INFO com.hdu.Main - 开始执行任务.....
//00:31:50.700 [pool-1-thread-1] INFO com.hdu.Main - 执行任务完毕, 返回结果 : hello world
//00:31:50.701 [Thread-0] INFO com.hdu.Main - 拿到执行结果 : hello world
//00:31:50.701 [Thread-3] INFO com.hdu.Main - 拿到执行结果 : hello world
//00:31:50.701 [Thread-2] INFO com.hdu.Main - 拿到执行结果 : hello world
//00:31:50.701 [Thread-1] INFO com.hdu.Main - 拿到执行结果 : hello world
}
这里你需要注意一个误区,并不是只有一个线程能调用 get() 方法,所有线程都能调用 get() 方法。
2. 一图胜千言
调用 future.get()的线程
调用 future.get() 的线程会把当前线程加入到一个链表中,然后阻塞等待任务结果。
执行任务的线程
执行任务的线程完成任务之后,会调用 set(执行过程中没有出现异常), setException(执行过程中出现了异常)。无论是调用 set() 还是调用 setException() 内部都会遍历链表,然后唤醒每一个等待任务结果的阻塞线程。
3. 源码解析
run()
任务执行逻辑
public void run() {
// state != NEW 说明当前task已经被执行过了,或者被取消了,总之非 NEW 状态的任务,线程就不处理了
// !UNSAFE.compareAndSwapObject(this, runnerOffset CAS 设置执行当前任务的线程,如果失败,说明任务被其他线程抢占了
null, Thread.currentThread()))
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
// 这里还需要判断 state == NEW 是因为防止外部线程 cancel掉该任务
if (c != null && state == NEW) {
V result;
boolean ran;
try {
// 执行任务
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
// 任务正常执行 设置执行结果
set(result);
}
} finally {
runner = null;
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
set()
成功执行完成任务之后 set 结果
protected void set(V v) {
// CAS 方式设置 任务执行状态为 COMPLETING
// 这里有一定的概率失败,比如刚好执行这里,然后外部线程 cancel 任务
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = v;
// 状态修改为 NORMAL
UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
finishCompletion();
}
}
setException()
线程执行的过程中出现异常, set 异常
protected void setException(Throwable t) {
// CAS 方式设置 任务执行状态为 COMPLETING
// 这里有一定的概率失败,比如刚好执行这里,然后外部线程 cancel 任务
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = t;
UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
finishCompletion();
}
}
finishCompletion()
唤醒链表里面所有阻塞等待的线程
private void finishCompletion() {
// assert state > COMPLETING;
for (WaitNode q; (q = waiters) != null;) {
if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
for (;;) {
Thread t = q.thread;
if (t != null) {
q.thread = null;
LockSupport.unpark(t);
}
WaitNode next = q.next;
if (next == null)
break;
q.next = null; // unlink to help gc
q = next;
}
break;
}
}
done();
callable = null; // to reduce footprint
}
get()
阻塞等待获取任务结果。
public V get() throws InterruptedException, ExecutionException {
int s = state;
// 条件成立 : 未执行,正在执行,正完成。调用 get的外部线程会被阻塞在get方法上。
if (s <= COMPLETING)
s = awaitDone(false, 0L);
return report(s);
}
awaitDone()
将自己封装为 waitNode 节点加到链表中,等待被唤醒
private int awaitDone(boolean timed, long nanos)
throws InterruptedException {
// 0 不带超时
final long deadline = timed ? System.nanoTime() + nanos : 0L;
// 引用当前线程 封装成WaitNode
WaitNode q = null;
boolean queued = false;
// 自旋
for (;;) {
// 条件成立 :该线程被其他线程中断
if (Thread.interrupted()) {
// 将节点移除链表
removeWaiter(q);
// 抛出异常
throw new InterruptedException();
}
// 被执行任务的线程使用 unpark api 唤醒
// 获取当前任务的最新状态
int s = state;
if (s > COMPLETING) {
// 当前任务已经有结果了
if (q != null)
q.thread = null;
// 返回当前任务的状态
return s;
}
// 条件成立 :说明任务马上完成了,释放cpu,下一次继续争抢。
else if (s == COMPLETING) // cannot time out yet
Thread.yield();
// 条件成立 :第一次自旋,当前线程还没有创建 WaitNode 对象,此时为当前线程创建 WaitNode对象
else if (q == null)
q = new WaitNode();
// 条件成立 :第二次自旋,线程已经创建了 waitNode对象,但是waitNode对象还没入队,此时需要做入队操作
else if (!queued)
// 当前线程 node 节点 指向 原队列的头节点 。waiters 一直指向队列的头
queued = UNSAFE.compareAndSwapObject(this, waitersOffset,q.next = waiters, q);
// 带超时时间的 park
else if (timed) {
nanos = deadline - System.nanoTime();
if (nanos <= 0L) {
removeWaiter(q);
return state;
}
LockSupport.parkNanos(this, nanos);
}
else
// 当前get操作的线程被park住
// 除非有其他线程唤醒执行任务的线程 或者当前线程被中断
LockSupport.park(this);
}
}
cancel()
该方法会取消任务,会中断执行任务的线程,但是你的任务处理逻辑里面需要响应线程中断才能成功让线程中断。
public boolean cancel(boolean mayInterruptIfRunning) {
if (!(state == NEW &&
UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
return false;
try { // in case call to interrupt throws exception
if (mayInterruptIfRunning) {
try {
Thread t = runner;
if (t != null)
// 中断任务
t.interrupt();
} finally { // final state
UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
}
}
} finally {
// 唤醒所有等待结果的阻塞线程
finishCompletion();
}
return true;
}
4. FutureTask增强
JDK 提供的 FutureTask 没不能很好的感知任务执行过程中成功,或者失败,或者取消。所以我们可以对 Future 进行增强。
使用示例
public static void testEnhanceFutureTask2() throws InterruptedException {
ExecutorService executorService = Executors.newSingleThreadExecutor();
EnhanceFutureTask<String> enhanceTask = buildEnhanceTask(()->{
TimeUnit.SECONDS.sleep(1);
return "hello world";
});
executorService.execute(enhanceTask);
//01:10:49.965 [pool-1-thread-1] INFO com.hdu.Main - 触发成功回调, 任务执行结果 : hello world
//01:10:49.967 [pool-1-thread-1] INFO com.hdu.Main - 触发finally回调, 任务执行结果/异常 : hello world
}
public static void testEnhanceFutureTask() throws InterruptedException {
ExecutorService executorService = Executors.newSingleThreadExecutor();
EnhanceFutureTask<String> enhanceTask = buildEnhanceTask(()->{
try {
TimeUnit.SECONDS.sleep(15);
}
catch (InterruptedException e) {
log.info("任务被取消了");
throw e;
}
return "hello world";
});
executorService.execute(enhanceTask);
TimeUnit.SECONDS.sleep(1);
enhanceTask.cancel(true);
//01:11:59.451 [pool-1-thread-1] INFO com.hdu.Main - 任务被取消了
//01:11:59.451 [main] INFO com.hdu.Main - 任务被取消
//01:11:59.452 [pool-1-thread-1] INFO com.hdu.Main - 触发失败回调, 任务执行异常 : sleep interrupted
//01:11:59.453 [pool-1-thread-1] INFO com.hdu.Main - 触发finally回调, 任务执行结果/异常 : sleep interrupted
}
public static EnhanceFutureTask<String> buildEnhanceTask(Callable<String> callable) {
return EnhanceFutureTask.of(callable)
.addSuccessListener((task) -> log.info("触发成功回调, 任务执行结果 : {}" , task.getResult()))
.addFinallyListener(
(task) -> log.info(
"触发finally回调, 任务执行结果/异常 : {}", task.getResult() != null
? task.getResult()
: task.getException().getMessage()
)
)
.addFailureListener((task) -> log.info("触发失败回调, 任务执行异常 : {}", task.getException().getMessage()))
.addCancelListener((task) -> log.info("任务被取消"));
}
源码
实现原理很简单,其实就是 继承 FutureTask,然后 重写 set,setException,cancel逻辑,在这些方法里面回调我们添加的监听器。
package com.hdu;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import static java.util.Optional.ofNullable;
public class EnhanceFutureTask<V> extends FutureTask<V> {
private List<FutureListener<EnhanceFutureTask<V>>> successListeners;
private List<FutureListener<EnhanceFutureTask<V>>> failureListeners;
private List<FutureListener<EnhanceFutureTask<V>>> cancelListeners;
private List<FutureListener<EnhanceFutureTask<V>>> finallyListeners;
private V res;
private Throwable t;
public EnhanceFutureTask(Callable<V> callable) {
super(callable);
}
public static <V> EnhanceFutureTask<V> of(Callable<V> callable) {
return new EnhanceFutureTask<>(callable);
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
boolean result = super.cancel(mayInterruptIfRunning);
invokeListeners(cancelListeners);
return result;
}
@Override
protected void set(V v) {
super.set(v);
res = v;
invokeListeners(successListeners);
invokeListeners(finallyListeners);
}
@Override
protected void setException(Throwable t) {
super.setException(t);
this.t = t;
invokeListeners(failureListeners);
invokeListeners(finallyListeners);
}
public V getResult() {
return res;
}
public Throwable getException() {
return t;
}
public EnhanceFutureTask<V> addSuccessListener(FutureListener<EnhanceFutureTask<V>> listener) {
if (successListeners == null) {
successListeners = new ArrayList<>();
}
successListeners.add(listener);
return this;
}
public EnhanceFutureTask<V> addFailureListener(FutureListener<EnhanceFutureTask<V>> listener) {
if (failureListeners == null) {
failureListeners = new ArrayList<>();
}
failureListeners.add(listener);
return this;
}
public EnhanceFutureTask<V> addCancelListener(FutureListener<EnhanceFutureTask<V>> listener) {
if (cancelListeners == null) {
cancelListeners = new ArrayList<>();
}
cancelListeners.add(listener);
return this;
}
public EnhanceFutureTask<V> addFinallyListener(FutureListener<EnhanceFutureTask<V>> listener) {
if (finallyListeners == null) {
finallyListeners = new ArrayList<>();
}
finallyListeners.add(listener);
return this;
}
private void invokeListeners(List<FutureListener<EnhanceFutureTask<V>>> listeners) {
ofNullable(listeners)
.ifPresent(listenerList -> listenerList.forEach(listener -> listener.handle(this)));
}
}