FutureTask源码解析,以及增强适配

133 阅读6分钟

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. 一图胜千言

futureTask.png

调用 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)));
    }


}

5. 源码

future_task_enhance: future_task_enhance (gitee.com)