Java8源碼閱讀 - Executor、ExecutorService、ExecutorCompletionService

Executor

public interface Executor {
    void execute(Runnable command);
}

Executor抽象提供了一種將任務提交與每個任務的運行機制(包括線程使用、調度)分離的方法,即Runnable代表任務,execute處理調度的邏輯;

static class ThreadPerTaskExecutor implements Executor {
    public void execute(Runnable r) {
        System.out.println("ThreadPerTaskExecutor - execute"); 
        new Thread(r).start();
    }
}

static class DirectExecutor implements Executor {
    public void execute(Runnable r) {
        System.out.println("DirectExecutor - execute");
        r.run();
    }
}

class SerialExecutor implements Executor {
    final Queue<Runnable> tasks = new ArrayDeque<Runnable>();
    final Executor executor;
    Runnable active;
    SerialExecutor(Executor executor) {
        this.executor = executor;
    }
    public synchronized void execute(final Runnable r) {
        System.out.println("task offer ... ");
        tasks.offer(new Runnable() {
            public void run() {
                System.out.println("SerialExecutor - execute ... ");
                try {
                    r.run();
                } finally {
                    scheduleNext();
                }
            }
        });
        if (active == null) {
            scheduleNext();
        }
    }
    protected synchronized void scheduleNext() {
        if ((active = tasks.poll()) != null) {
            System.out.println("schedule next task ");
            executor.execute(active);
        }
    }
}

public static void main(String[] args) {
    // SerialExecutor executor = new SerialExecutor(new ThreadPerTaskExecutor());
    SerialExecutor executor = new SerialExecutor(new DirectExecutor());
    executor.execute(() -> { System.out.println(Thread.currentThread()); });
    executor.execute(() -> { System.out.println(Thread.currentThread()); });
}

#輸出
#task offer ... 
#schedule next task 
#DirectExecutor - execute
#SerialExecutor - execute ... 
#Thread[main,5,main]
#task offer ... 
#schedule next task 
#DirectExecutor - execute
#SerialExecutor - execute ... 
#Thread[main,5,main]

官方文檔上提供的示例,演示了Executor抽象的簡單使用方法,示例想體現(xiàn)的除了異步同步任務外,我覺得更加重要的是任務執(zhí)行和任務調度分離的思想;

ExecutorService

public interface ExecutorService extends Executor {
    // 啟動有序關閉,在此過程中執(zhí)行以前提交的任務,但不接受任何新任務。
    void shutdown();
    // 嘗試停止所有正在執(zhí)行的任務,停止等待任務的處理,并返回等待執(zhí)行的任務列表。
    List<Runnable> shutdownNow();
    // executor是否被shutdown
    boolean isShutdown();
    // 如果所有任務都完成關閉則返回true
    boolean isTerminated();
    //  阻塞直到所有任務在關閉請求后完成執(zhí)行,或超時發(fā)生后,或當前線程中斷后;
    boolean awaitTermination(long timeout, TimeUnit unit)
        throws InterruptedException;
    // 提交任務,返回
    <T> Future<T> submit(Callable<T> task);
    <T> Future<T> submit(Runnable task, T result);
    Future<?> submit(Runnable task);
    // 執(zhí)行一個集合的任務,返回一個列表其中包含所有任務完成時的狀態(tài)和結果(可以是異常結果)。
    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
        throws InterruptedException;
    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                                  long timeout, TimeUnit unit)
        throws InterruptedException;
    // 執(zhí)行給定的任務,返回已成功完成的任務的結果(即不拋出異常),如果有的話。在正常或異常返回時,未完成的任務將被取消。
    <T> T invokeAny(Collection<? extends Callable<T>> tasks)
        throws InterruptedException, ExecutionException;
    <T> T invokeAny(Collection<? extends Callable<T>> tasks,
                    long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

ExecutorService提供了對每個Executor跟蹤、管理一個或者多個異步任務的進度,也可以關閉服務來終止service接收新任務和回收資源;

void shutdownAndAwaitTermination(ExecutorService pool) {
    pool.shutdown(); // 禁止提交新任務
    try {
        //等待現(xiàn)有任務終止
        if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
            pool.shutdownNow(); // 取消當前正在執(zhí)行的任務
            // 等待一段時間,等待任務響應被取消
            if (!pool.awaitTermination(60, TimeUnit.SECONDS)) 
                System.err.println("Pool did not terminate");
        }
    } catch (InterruptedException ie) {
        // 如果當前線程處于中斷狀態(tài),重試shutdown
        pool.shutdownNow();
        // 保存中斷狀態(tài)
        Thread.currentThread().interrupt();
    }
}

文檔中演示了一個終止服務的示例,分兩個階段關閉一個 ExecutorService,首先需要調用shutdown來拒絕傳入的任務,然后調用shutdownNow(如果需要的話)來取消任何延遲的任務;

CompletionService

public interface CompletionService<V> {
    Future<V> submit(Callable<V> task);
    Future<V> submit(Runnable task, V result);
    Future<V> take() throws InterruptedException;
    Future<V> poll();
    Future<V> poll(long timeout, TimeUnit unit) throws InterruptedException;
}

CompletionService旨在提供一個異步任務產生執(zhí)行和已完成任務結果的解耦服務,即會有一個隊列儲存已完成的任務結果的合集,任務的提交和執(zhí)行不會阻塞獲取結果操作;

ExecutorCompletionService

public class ExecutorCompletionService<V> implements CompletionService<V> {
    private final Executor executor;
    private final AbstractExecutorService aes;
    private final BlockingQueue<Future<V>> completionQueue;
    ... 
}

ExecutorCompletionServiceCompletionService的實現(xiàn)類,內部有個阻塞隊列儲存的是完成任務的結果;

// 注意這個queue的默認長度為Integer.MAX_VALUE
public ExecutorCompletionService(Executor executor) {
    if (executor == null)
        throw new NullPointerException();
    this.executor = executor;
    this.aes = (executor instanceof AbstractExecutorService) ?
        (AbstractExecutorService) executor : null;
    this.completionQueue = new LinkedBlockingQueue<Future<V>>();
}

public ExecutorCompletionService(Executor executor,
                                 BlockingQueue<Future<V>> completionQueue) {
    if (executor == null || completionQueue == null)
        throw new NullPointerException();
    this.executor = executor;
    this.aes = (executor instanceof AbstractExecutorService) ?
        (AbstractExecutorService) executor : null;
    this.completionQueue = completionQueue;
}

構造器默認使用LinkedBlockingQueue,那么很容易就聯(lián)想到該阻塞隊列的特性:

  • 是有界的雙端隊列
  • 提供阻塞和非阻塞方法獲取已完成的任務
public Future<V> take() throws InterruptedException {
    return completionQueue.take();
}
public Future<V> poll() {
    return completionQueue.poll();
}
public Future<V> poll(long timeout, TimeUnit unit)
        throws InterruptedException {
    return completionQueue.poll(timeout, unit);
}
  • 當完成任務的隊列滿了,新完成的任務結果會被拋棄
private class QueueingFuture extends FutureTask<Void> {
    QueueingFuture(RunnableFuture<V> task) {
        super(task, null);
        this.task = task;
    }
    // FutureTask提供的鉤子
    protected void done() { completionQueue.add(task); }
    private final Future<V> task;
}

注意這里的doneFutureTask完成或者異?;蛘?code>cancel都會被調用;

public Future<V> submit(Callable<V> task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<V> f = newTaskFor(task);
    executor.execute(new QueueingFuture(f));
    return f;
}
private RunnableFuture<V> newTaskFor(Callable<V> task) {
    if (aes == null)
        return new FutureTask<V>(task);
    else
        return aes.newTaskFor(task);
}

若構造器中傳進來的ExecutorAbstractExecutorService的子類,那么newTaskFor就會交由子類來決定FutureTask的類型,達到定制擴展的效果;

void solve(Executor e, Collection<Callable<Result>> solvers) 
        throws InterruptedException, ExecutionException {
    CompletionService<Result> ecs = new ExecutorCompletionService<Result>(e);
    for (Callable<Result> s : solvers) 
        ecs.submit(s);
        int n = solvers.size();
        for (int i = 0; i < n; ++i) { 
            Result r = ecs.take().get(); // 這里會拋出中斷異常
            if (r != null) 
                use(r);
        } 
}

官方提供的用法示例,第一個比較簡單,遍歷任務集合中每個任務執(zhí)行后獲取結果,是一種順序執(zhí)行的過程,執(zhí)行 -> 獲取結果 -> 執(zhí)行 -> 獲取結果,當然執(zhí)行任務過程可以是異步的,如果遇到中斷異常會停止任務;

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容