1. 程式人生 > >[Java併發包學習一]Executor和ExecutorService

[Java併發包學習一]Executor和ExecutorService

本文介紹jdk8併發包中的Executor/ExecutorService這兩個介面。

Executor介面

概述

該類提供一個提交任務的方法,提交的任務可以在提交程式本執行緒執行,也可以在不同的執行緒執行,也可以在一個執行緒池中的執行緒執行,全看如何使用。

However, the {@code Executor} interface does not strictly
require that execution be asynchronous. In the simplest case, an executor can run the submitted task immediately in the caller’s thread

然而,該介面並沒有嚴格規定提交的任務是非同步執行的,最簡單的情況,提交的任務可以直接由任務的caller thread執行。

More typically, tasks are executed in some thread other
than the caller’s thread. The executor below spawns a new thread for each task

更典型的情況是提交的任務並不是由caller thread執行,而是建立了新的執行緒去執行,比如執行緒池。

execute方法

該介面提供一個方法:

1
void execute(Runnable command)
;

該方法的作用是提交一個任務,這個任務在未來的某一時刻會被執行,該任務可能被新的執行緒執行,可能被執行緒池中的執行緒執行,也有可能就被提交者本身的執行緒執行。

ExecutorService介面

概述

ExecutorService繼承於Executor,它提供一些可以管理任務的執行、取消、結束的方法。

shutdown方法

1
void shutdown();

shutdown方法呼叫之後,馬上拒絕接收新的任務,但是之前已經提交的任務會繼續執行。

shutdownNow方法

1
List<Runnable> shutdownNow();

該函式呼叫之後,馬上拒絕接收新的任務,並且會嘗試結束當前正在執行的任務,直到所有任務真正結束為止,並且會返回等待執行的任務的列表。

isShutdown方法

1
boolean isShutdown();

該函式判斷service是否已經被shutdown,如果呼叫過shutdown函式,則返回true,否則返回false。

isTerminated方法

1
boolean isTerminated();

該函式判斷service中得所有任務是否已經全部執行完畢,並且應該注意的是:如果沒有呼叫過shutdown函式或者shutdownNow函式,該函式的返回值不可能為true。

awaitTermination方法

1
2
boolean awaitTermination(long timeout, TimeUnit unit)
        throws InterruptedException;

該函式會一直阻塞直到所有的任務已經被執行或者等待時間到。

submit方法

1
2
3
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);

這些函式都是向service提交一個任務,並且返回一個Futrue物件,用於追蹤任務的執行情況。區別在於第一個函式在任務執行完畢之後Futrue.get()將會返回任務執行的結果,第二個函式在任務執行完畢之後Future.get()將會返回給定的result結果,而第三個函式在任務執行完畢之後Future.get()將會返回null。

invokeAll方法

1
2
3
4
<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;

這些方法比較好理解,就是執行任務列表中的所有任務,並返回與每個任務對應的Futue。也就是說,任務彼此之間不會相互影響,可以通過future跟蹤每一個任務的執行情況,比如是否被取消,是正常完成,還是異常完成,這主要使用Future類提供的API。invokeAll是一個阻塞方法,會等待任務列表中的所有任務都執行完成。不管任務是正常完成,還是異常終止,Future.isDone()始終返回true。通過
Future.isCanceled()可以判斷任務是否在執行的過程中被取消。通過Future.get()可以獲取任務的返回結果,或者是任務在執行中丟擲的異常。

invokeAny方法

1
2
3
4
5
<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;

上面的函式執行給定的一系列任務,當某一個任務成功執行(沒有丟擲異常)時,返回該任務對應的Future物件,其他所有未被執行的任務都將取消。如果執行過程中修改了tasks列表,則返回的結果是不確定的。第二個函式帶有超時時間。此外還應該注意:

  • 一旦有1個任務正常完成(執行過程中沒有拋異常),執行緒池會終止>其他未完成的任務 。
  • 如果提交的任務列表中,沒有1個正常完成的任務,那麼呼叫invokeAny會拋異常,究竟拋的是哪兒個任務的異常,無關緊要
  • invokeAny()和任務的提交順序無關,只是返回最早正常執行完成的任務
  • 如果在超時之前,所有任務已經都是異常終止,那就沒有必要在等下去了;如果超時之後,仍然有正在執行或等待執行的任務,那麼會丟擲TimeoutException。