1.Runnable接口
The Runnable interface should be implemented by any class
whose instances are intended to be executed by a thread. The
class must define a method of no arguments called run.
This interface is designed to provide a common protocol for
objects that wish to execute code while they are active. For
example, Runnable is implemented by class Thread. Being active
simply means that a thread has been started and has not yet
been stopped.
In addition, Runnable provides the means for a class to be active
while not subclassing Thread. A class that implements Runnable
can run without subclassing Thread by instantiating a Thread
instance and passing itself in as the target. In most cases, the
Runnable interface should be used if you are only planning to
override the run() method and no other Thread methods. This is
important because classes should not be subclassed unless the
programmer intends on modifying or enhancing the fundamental
behavior of the class.
Runnable接口由如下類實現:該類需要被線程執行。該類需要定義一個無參方法run。
Runnable提供了一種不是繼承Thread的方式。在大多數情況下,如果僅僅是覆寫run方法而不是其他Thread方法,則應該使用Runnable接口。除非打斷修改或增強類的基本行爲,否則不應該對類進行子類化。
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
2.Callable接口
A task that returns a result and may throw an exception.
Implementors define a single method with no arguments called
call.
The Callable interface is similar to Runnable, in that both are
designed for classes whose instances are potentially executed by
another thread. A Runnable, however, does not return a result
and cannot throw a checked exception.
The Executors class contains utility methods to convert from
other common forms to Callable classes.
返回結果或拋出異常的任務,實現者定義一個無參call方法。
與Runnable接口類似,該類實例可能由另一個線程執行。但是Runnable不能返回結果或拋出受查異常。
Executors類包含將其他常用形式轉換爲Callable類的實用方法。
@FunctionalInterface
public interface Callable<V> {
V call() throws Exception;
}
3.Future
A Future represents the result of an asynchronous computation.
Methods are provided to check if the computation is complete, to
wait for its completion, and to retrieve the result of the
computation. The result can only be retrieved using method get
when the computation has completed, blocking if necessary until
it is ready. Cancellation is performed by the cancel method.
Additional methods are provided to determine if the task
completed normally or was cancelled. Once a computation has
completed, the computation cannot be cancelled. If you would
like to use a Future for the sake of cancellability but not provide a
usable result, you can declare types of the form Future<?> and
return null as a result of the underlying task.
Future表示異步計算的結果。提供檢查計算是否完成、等待計算完成以及取出計算結果的方法。只有在計算完成時,get方法才能取到結果,必要時會阻塞直到其計算完成。cacel方法執行取消動作。提供了其他方法檢測任務是正常完成還是被取消。當計算完成後,其不能被取消。如果爲了取消而不是提供有用結果而使用Future,可以聲明Future<?>形式的類型,並返回null。
示例用法(如下的類都是虛構的):
interface ArchiveSearcher { String search(String target); }
class App {
ExecutorService executor = ...
ArchiveSearcher searcher = ...
void showSearch(final String target)
throws InterruptedException {
Future<String> future
= executor.submit(new Callable<String>() {
public String call() {
return searcher.search(target);
}});
displayOtherThings(); // do other things while searching
try {
displayText(future.get()); // use future
} catch (ExecutionException ex) { cleanup(); return; }
}
}
FutureTask類是Future的一個實現,並實現了Runnable,因此可以由Executor執行。上述帶submit結構可由下面的形式代替:
FutureTask<String> future =
new FutureTask<String>(new Callable<String>() {
public String call() {
return searcher.search(target);
}});
executor.execute(future);
如下爲Future的完整形式:
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
關於cancle方法的說明:
- 在任務已經完成、已經被取消或者由於其他原因不能被取消時,取消會失敗。
- 任務還未啓動時調用cacel,會成功,並且任務永遠都不能運行
- 任務已經啓動了,mayInterruptIfRunning 參數會決定執行該任務的線程是否會被中斷,以中斷該任務
- 該方法返回後,後續的isDone()調用總是返回true。如果該方法返回true,後續的isCancelled()總是返回true。
4.RunnableFuture
A Future that is Runnable. Successful execution of the run
method causes completion of the Future and allows access to its
results.
是Runnable的Future,成功執行run方法將使Future完成,並允許訪問其他結果。
public interface RunnableFuture<V> extends Runnable, Future<V> {
/**
* Sets this Future to the result of its computation
* unless it has been cancelled.
*/
void run();
}
5.FutureTask
A cancellable asynchronous computation. This class provides a
base implementation of Future, with methods to start and cancel
a computation, query to see if the computation is complete, and
retrieve the result of the computation. The result can only be
retrieved when the computation has completed; the get methods
will block if the computation has not yet completed. Once the
computation has completed, the computation cannot be restarted
or cancelled (unless the computation is invoked using
runAndReset()).
A FutureTask can be used to wrap a Callable or Runnable object.
Because FutureTask implements Runnable, a FutureTask can be
submitted to an Executor for execution.
In addition to serving as a standalone class, this class provides
protected functionality that may be useful when creating
customized task classes.
可取消的異步計算。此類提供了Future的基本實現,包括啓動和取消計算的方法,查詢計算是否完成的查詢,以及檢索計算結果。 只有在計算完成後才能檢索結果; 如果計算尚未完成,get方法將阻塞。 計算完成後,無法重新啓動或取消計算(除非使用runAndReset()調用計算)。
FutureTask可用於包裝Callable或Runnable對象。 因爲FutureTask實現了Runnable,所以可以將FutureTask提交給Executor執行。
除了作爲獨立類之外,此類還提供了在創建自定義任務類時可能有用的保護方法。
Revision notes: This differs from previous versions of this
class that relied on AbstractQueuedSynchronizer, mainly to
avoid surprising users about retaining interrupt status during
cancellation races. Sync control in the current design relies
on a "state" field updated via CAS to track completion, along
with a simple Treiber stack to hold waiting threads.
Style note: As usual, we bypass overhead of using
AtomicXFieldUpdaters and instead directly use Unsafe intrinsics.
修訂說明:之前版本依賴於AQS,現版本主要是爲了避免在取消爭用期間保留中斷狀態。當前設計中的同步控制依賴於通過CAS更新state域來跟蹤完成,以及用於保存等待線程簡單的Treiber棧。
樣式說明:像之前一樣,繞過了使用AtomicXFieldUpdaters的開銷,而是直接使用Unsafe內部方法。
5.1 狀態的變化
/**
* The run state of this task, initially NEW. The run state
* transitions to a terminal state only in methods set,
* setException, and cancel. During completion, state may take on
* transient values of COMPLETING (while outcome is being set) or
* INTERRUPTING (only while interrupting the runner to satisfy a
* cancel(true)). Transitions from these intermediate to final
* states use cheaper ordered/lazy writes because values are unique
* and cannot be further modified.
*
* Possible state transitions:
* NEW -> COMPLETING -> NORMAL
* NEW -> COMPLETING -> EXCEPTIONAL
* NEW -> CANCELLED
* NEW -> INTERRUPTING -> INTERRUPTED
*/
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;
任務的運行狀態初始化爲NEW。任務狀態轉爲終止狀態只會發生在方法set setException和cancel方法。在完成期間,state可能會一個短暫的COMPLETING或者INTERRUPTING。從這些中間狀態到最終狀態的轉換使用更便宜的ordered/惰性寫入,因爲值是唯一的並且不能進一步修改。
可能的狀態轉換:
- NEW -> COMPLETING -> NORMAL
- NEW -> COMPLETING -> EXCEPTIONAL
- NEW -> CANCELLED
- NEW -> INTERRUPTING -> INTERRUPTED
5.2 構造器及域
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) {
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
如果不需要結果,考慮使用下面的形式:
Future<?> f = new FutureTask<Void>(runnable, null);
從構造器可以看出,任務的初始狀態爲NEW。
/** The underlying callable; nulled out after running */
private Callable<V> callable;
/** The result to return or exception to throw from get() */
private Object outcome; // non-volatile, protected by state reads/writes
/** The thread running the callable; CASed during run() */
private volatile Thread runner;
/** Treiber stack of waiting threads */
private volatile WaitNode waiters;
- callable代表執行的任務,運行後置爲null;
- outcome代表返回結果或者要拋出的異常,從get()獲取的
- runner代表運行callable的線程,在run()中CAS賦值
- waiters代表等待線程的Treiber棧
5.3 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 {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
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);
}
}
- step1.線程狀態不爲NEW時返回;設置任務的runner爲當前線程
- step2.運行任務result = c.call()
正常運行完成後,set(result)
發生異常,setException(ex) - step3.運行完成後,設置runner = null
重新讀取state以防有漏掉的中斷:s >= INTERRUPTING時,會調用handlePossibleCancellationInterrupt(s)
runner作爲鎖使用,防止其他線程併發調用run:
- run之前首先通過CAS嘗試獲得鎖,並將runner置爲當前線程
- run之後通過將runner = null釋放鎖
protected void set(V v) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = v;
UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
finishCompletion();
}
}
protected void setException(Throwable t) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = t;
UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
finishCompletion();
}
}
從上面可以看出,run有兩條狀態轉移路線:
- 1)正常運行set(result)
NEW -> COMPLETING -> NORMAL - 2)發生異常
NEW -> COMPLETING -> EXCEPTIONAL
關於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
}
- step1.將waiters置爲null
- step2.逐個喚醒在棧中阻塞的線程LockSupport.unpark(t)
- step3.調用保護方法done(),子類可以實現已完成想要的功能
- step4.將callable置爲null
5.4 get
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
s = awaitDone(false, 0L);
return report(s);
}
- step1.如果任務還沒有完成,則調用awaitDone
- step2.任務完成,則report(s)
private int awaitDone(boolean timed, long nanos)
throws InterruptedException {
final long deadline = timed ? System.nanoTime() + nanos : 0L;
WaitNode q = null;
boolean queued = false;
for (;;) {
if (Thread.interrupted()) {
removeWaiter(q);
throw new InterruptedException();
}
int s = state;
if (s > COMPLETING) {
if (q != null)
q.thread = null;
return s;
}
else if (s == COMPLETING) // cannot time out yet
Thread.yield();
else if (q == null)
q = new WaitNode();
else if (!queued)
queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
q.next = waiters, q);
else if (timed) {
nanos = deadline - System.nanoTime();
if (nanos <= 0L) {
removeWaiter(q);
return state;
}
LockSupport.parkNanos(this, nanos);
}
else
LockSupport.park(this);
}
}
- step1.如果發生中斷,則removeWaiter(q),並拋出異常
- step2.如果已經完成,則返回狀態
- step3.狀態爲COMPLETING(表示已經執行完了,正在最後的設置期間),則調用Thread.yield(),因爲當前線程是get,一般是另外的線程在執行任務,所以讓執行任務的線程優先獲得執行權限
- step4.狀態爲< COMPLETING,此時任務還在執行,則創建q = WaitNode()
- step5.如果創建的q沒有入隊,則入隊,並置於隊首,即入棧
- step6.最當前線程進行進行阻塞
static final class WaitNode {
volatile Thread thread;
volatile WaitNode next;
WaitNode() { thread = Thread.currentThread(); }
}
5.5 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;
}
- step1.不是NEW狀態,直接返回false,表示此時任務已經執行完了
- step2.爲NEW狀態,如果 mayInterruptIfRunning 爲false
NEW - > CANCELLED - step3.爲NEW狀態,如果 mayInterruptIfRunning 爲true
NEW -> INTERRUPTING -> INTERRUPTED
並會對運行任務的runner進行中斷
6.爲什麼FutureTask不再基於AQS
ThreadPoolExecutor executor = ...;
executor.submit(task1).cancel(true);
executor.submit(task2);
雖然中斷的是task1,但可能task2得到中斷信號。
JDK1.6的 FutureTask.Sync.innerCancel的代碼:
boolean innerCancel(boolean mayInterruptIfRunning) {
for (;;) {
int s = getState();
if (ranOrCancelled(s))
return false;
if (compareAndSetState(s, CANCELLED))
break;
}
if (mayInterruptIfRunning) {
Thread r = runner;
if (r != null) //1
r.interrupt(); //2
}
releaseShared(0);
done();
return true;
}
按照如下的執行流程,task2得到中斷信號:
- step1.主線程調用cancel(true)想取消task1,執行完1處檢查後,停住
- step2.Thread1執行完task1,開始執行task2
- step3.主線程此時繼續執行2處的r.interrupt(),那麼task2將會被中斷
看看新版本怎麼處理這個中斷遺留問題:
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;
}
run最後的代碼:
} 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);
}
/**
* Ensures that any interrupt from a possible cancel(true) is only
* delivered to a task while in run or runAndReset.
*/
private void handlePossibleCancellationInterrupt(int s) {
// It is possible for our interrupter to stall before getting a
// chance to interrupt us. Let's spin-wait patiently.
if (s == INTERRUPTING)
while (state == INTERRUPTING)
Thread.yield(); // wait out pending interrupt
// assert state == INTERRUPTED;
// We want to clear any interrupt we may have received from
// cancel(true). However, it is permissible to use interrupts
// as an independent mechanism for a task to communicate with
// its caller, and there is no way to clear only the
// cancellation interrupt.
//
// Thread.interrupted();
}
可知run最後對此進行了特別處理:
- 如果該任務已經被取消,且未被取消完成,則handlePossibleCancellationInterrupt(s)
- handlePossibleCancellationInterrupt其實很簡單,就是在主線cancel()完成之前,在這裏自旋,Thread.yield()讓執行取消的主線程更容易獲得執行機會。
這裏根本就是在主線程執行取消指定任務時,讓執行該取消任務的線程自旋等待 主線程中斷操作 完成。