FutureTask类
Look under the inheritance graph FutureTask class, it also implements Future class and Runnable class, which means it can actually be used as a Runable passed to the Thread class execution
FutureTask can be seen by the constructor of the class to initialize the interface requires a Callable
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
复制代码
A review article [JUC source code analysis] __ ThreadPoolExecutor class , when the thread pool submit a Callable object that AbstractExecutorService.submit
will be used to create a FutureTask Callable instance, the Worker thread pool thread will eventually implement this FutureTask the Runnable.run
method
FutureTask.get final method is how to get the return value of Callable.call?
Let's look at the source code FutureTask.get method
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
s = awaitDone(false, 0L);
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);
}
复制代码
When the state less COMPLETING
, the thread is blocked waiting for completion; otherwise it returns the call to report FutureTask the outcome
field. That FutureTask will eventually result in the preservation outcome
field
FutureTask is how to save the results to the outcome of callable field it?
Previous article mentioned the Worker thread pool thread will eventually implement this FutureTask the Runnable.run
method
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);
}
}
//为了方便起见把 outcome字段的定义写在这里
private Object outcome; // non-volatile, protected by state reads/writes
protected void set(V v) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = v;
UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
finishCompletion();
}
}
复制代码
You can see when you call Callable.call
the method returns the result, will perform set(result)
the result set into the outcome
field here to see the beginning of time find it very strange:
- Why
outcome
field is not set tovolatile
? - Why
outcome = v;
set to take before the stateCOMPLETING
, andoutcome = v;
after they immediately set to the stateNORMAL
it?
Until the Internet to find the article why outcome object in FutureTask is non- volatile?
There is a very clever design that was passed in principle happends before use in java, so without the use of locks to ensure that other threads read state=NORMAL
when the thread must be able to read the latest value of the outcome of
When Future.get blocking method, when the task is how blocking threads are awakened?
Beginning of the article mentioned, calling FutureTask.get
upon the method, when the state less COMPLETING
, the thread is blocked waiting for completion
/** Treiber stack of waiting threads */
private volatile WaitNode waiters;
static final class WaitNode {
volatile Thread thread;
volatile WaitNode next;
WaitNode() { thread = Thread.currentThread(); }
}
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);
}
}
复制代码
Is a spin-operation, it is worth mentioning that this code:
else if (s == COMPLETING) // cannot time out yet
Thread.yield();
复制代码
In fact, this judgment is to deal with protected void set(V v)
the temporary state when FutureTask appear COMLETING state, in fact, the task has been carried over, but the thread switching occurs when you save the results, so only a very short wait can be used here Thread.yield()
to make a executive power threads
When the first cycle, if the task is not yet finished processing, it will create a new WaitNode
, WaitNode
save the current thread; when the second cycle, if the task is not out yet finished, this will be WaitNode
inserted into waiters
the top of the stack, and by calling LockSupport.parkNanos
or LockSupport.park
blocks the current thread. The thread is awakened by waiters
to wake up the stack to save the elements Thread. Here can be found, if there are multiple threads call FutureTask.get method and are blocked, then the thread will be inserted in order to call waiters
stack
How WaitNode wake blocked threads? In protected void set(V v)
the result of calls to save callable private void finishCompletion()
methods, procedures Through this method it is to put waiters
the stack in the order blocking thread LIFO to call one by one LockSupport.unpark
freed
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
}
复制代码