[Analysis of the JUC Source] __ a FutureTask, class

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.submitwill be used to create a FutureTask Callable instance, the Worker thread pool thread will eventually implement this FutureTask the Runnable.runmethod

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 outcomefield. That FutureTask will eventually result in the preservation outcomefield

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.runmethod

 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.callthe method returns the result, will perform set(result)the result set into the outcomefield here to see the beginning of time find it very strange:

  • Why outcomefield is not set to volatile?
  • Why outcome = v;set to take before the state COMPLETING, and outcome = v;after they immediately set to the state NORMALit?

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=NORMALwhen 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.getupon 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, WaitNodesave the current thread; when the second cycle, if the task is not out yet finished, this will be WaitNodeinserted into waitersthe top of the stack, and by calling LockSupport.parkNanosor LockSupport.parkblocks the current thread. The thread is awakened by waitersto 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 waitersstack

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 waitersthe stack in the order blocking thread LIFO to call one by one LockSupport.unparkfreed

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
    }
复制代码

reference

why outcome object in FutureTask is non-volatile?

Guess you like

Origin juejin.im/post/5e42dda5f265da570d735049