基本概念
線程Thread即表示要執行的任務,又表示執行的機制。
Java併發包提供了一套“異步任務執行服務”機制,將“任務的提交”和“任務的執行”相分離。
任務執行服務涉及到的基本接口:
- Runnable和Callable:表示要執行的異步任務
- Executor和ExecutorService:表示執行服務
- Future:表示異步任務的結果
Runnable和Callable都是接口,Runnable沒有返回結果,而Callable有,Runnable不會拋出異常,而Callable會。
Executor表示最簡單的執行服務
public interface Executor {
void execute(Runnable command);
}
可以執行一個Runnable,沒有返回結果。接口沒有限定任務如何執行,可能是創建一個新線程,可能是複用線程池中的某個線程
ExecutorService擴展了Executor,定了更多服務
先來看submit方法,submit表示提交一個任務,返回值類型都是Future,返回後,只是表示任務已提交,不代表已執行,通過Future可以查詢異步任務的狀態、獲取最終結果、取消任務等。
public interface ExecutorService extends Executor {
// 對於Callable,任務最終有個返回值
<T> Future<T> submit(Callable<T> task);
// Runnable是沒有返回值的,但可以提供一個結果,在異步任務結束時返回
<T> Future<T> submit(Runnable task, T result);
// 最終返回null
Future<?> submit(Runnable task);
}
再來看看Future的定義:
public interface Future<V> {
// 用於取消異步任務,如果任務已完成、或已取消、或由於某種原因不能取消,返回false,否則返回true
// 如果任務還未開始,則不再運行。如果任務已經在運行,則不一定能取消
// 參數mayInterruptIfRunning表示,如果任務正在執行,是否調用interrupt方法中斷線程,如果爲false就不會,如果爲true就會嘗試中斷線程,中斷不一定能取消線程
boolean cancel(boolean mayInterruptIfRunning);
// 表示任務是否被取消,只要cancel方法返回了true,隨後的isCancelled方法都會返回true,即使執行任務的線程還未真正結束
boolean isCancelled();
// 表示任務是否結算,不管什麼原因導致結束的
boolean isDone();
// 返回執行結果,如果任務是Runnable且沒有提供結果,返回null
// 任務被取消了,會拋出CancellationException
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}
基本使用
public class Test {
static class Task implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sleepSeconds = new Random().nextInt(1000);
Thread.sleep(sleepSeconds);
return sleepSeconds;
}
}
public static void main(String[] args) throws InterruptedException {
// 創建一個任務執行服務
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Integer> future = executor.submit(new Task());
Thread.sleep(100);
try {
System.out.println(future.get());
} catch (ExecutionException e) {
e.printStackTrace();
}
// 關閉任務執行服務
executor.shutdown();
}
}
ExecutorService還有如下幾個方法:
public interface ExecutorService extends Executor {
// 不再接受新任務,但已提交的任務會繼續執行,即使任務還未執行
void shutdown();
// 不接口新任務,且會終止已提交但未執行的任務,對於正在執行的任務,一般會調用線程的interrupt方法嘗試中斷
// 返回已提交但尚未執行的任務列表
List<Runnable> shutdownNow();
// showdown和showdownNow不會阻塞,它們返回後不代表所有任務都已結束,但isShutdown會返回ture
boolean isShutdown();
// 除非首先調用shutdown或shutdownNow,否則isTerminated永不爲true。
// 當調用shutdown()方法後,並且所有提交的任務完成後返回爲true;
// 當調用shutdownNow()方法後,成功停止後返回爲true;
boolean isTerminated();
// 等待所有任務結束,可以限定等待的時間
// 如果超時前所有任務都結束了,則返回true,否則返回false
boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;
// 等待所有任務完成,返回Future列表
// 每個Future的isDone都返回true,不過isDone不代表任務執行成功了,可能是被取消了
<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;
// 只要有一個任務返回成功了,就會返回該任務的結果,其他任務會被取消
<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的主要實現類是ThreadPoolExecutor,它是基於線程實現的,繼承於AbstractExecutorService
。AbstractExecutorService是一個抽象類,實現了ExecutorService的部分方法。
AbstractExecutorService
AbstractExecutorService提供了submit、invokeAll、invokeAny的默認實現,子類需要實現其他方法。
除了execute,其他方法都與執行服務的生命週期管理有關,submit/invokeAll/invokeAny最終都會調用execute,execute決定了到底如何執行任務。
我們可以先看看submit方法
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
調用newTaskFor生成了一個RunnableFuture,RunnableFuture是一個接口,既擴展了Runnable,又擴展了Future,沒有定義新的方法。作爲Runnable它表示要執行的任務,傳遞給execute進行執行;作爲Future它表示任務執行的異步結果。
我們再看看newTaskFor
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
return new FutureTask<T>(callable);
}
FutureTask實現了RunnableFuture接口
FutureTask
public class FutureTask<V> implements RunnableFuture<V> {
// 表示狀態
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;
// 表示待執行的任務
private Callable<V> callable;
// 表示最終的執行結果或異常
private Object outcome;
// 表示運行任務的線程
private volatile Thread runner;
// 單向鏈表,表示等待任務執行結果的線程
private volatile WaitNode waiters;
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) {
// 如果傳入的是runnable,則轉換爲callable
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
}
任務執行服務會使用一個線程執行FutureTask的run方法
public void run() {
if (state!= NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
// 調用callable的call方法
result = c.call();
ran = true;
} catch (Throwable ex) {
// 捕捉異常,異常保存到outcome並調用finishCompletion喚醒所有等待結果的線程
result = null;
ran = false;
setException(ex);
}
// 設置結果,保存到outcome並調用finishCompletion喚醒所有等待結果的線程
if (ran)
set(result);
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
任務提交者,通過get方法獲取結果,
public V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
if (unit == null)
throw new NullPointerException();
int s = state;
// 如果任務還未執行完畢就等待
if (s <= COMPLETING &&
(s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
throw new TimeoutException();
// 調用report報告結果,report根據狀態返回結果或拋出異常
return report(s);
}
private V report(int s) throws ExecutionException {
Object x = outcome;
if (s == NORMAL)
return (V)x;
if (s >= CANCELLED)
throw new CancellationException();
throw new ExecutionException((Throwable)x);
}