Java Callable 和 FutureTask详解

176 阅读1分钟

今天在使用JUC包中Callable实现线程时,比较好奇FutureTask类是如何阻断线程,以及是如何获得到返回值的。 记录一下研究过程。

先贴一段Demo代码。

import java.util.concurrent.*;

public class CallThread implements Callable<Integer>{
    public Integer call() {
        System.out.println("call()");
        return 0;
    }
    public static void main(String[] args) {

    CallThread mc = new CallThread();
    
    FutureTask<Integer> ft = new FutureTask<>(mc);
    Thread thread = new Thread(ft);
    try {
    } catch (Exception e) {
        //TODO: handle exception
    }
    
    thread.start();
    try {
        System.out.println("is Done:"+ft.isDone());
        System.out.println(ft.get());
        
        System.out.println("main()");
    } catch (Exception e) {
        e.printStackTrace();
    }
    
    }
}

运行是发现在调用ft.get()时 main线程会阻断等待其返回值。

比较好奇看一下源码。

FutureTask类中对get方法的实现是先判断下线程状态,然后等待结束,在return对象。

在源码中这样展示

    public V get() throws InterruptedException, ExecutionException {
        int s = state;
        if (s <= COMPLETING)
            s = awaitDone(false, 0L);
        return report(s);
    }

这里主要了解两个方法一个awaitDone和report

  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);
        }
    }

阅读这段代码大致可以了解其思路,无限循环轮询线程状态,进行阻断。 if (s > COMPLETING)这段代码表示了已完成以及出现异常或中断等都会执行下面代码逻辑会将state返回。

然后在看下是如何把对象返回的

    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);
    }

    /** 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

在outcome这里有对Callable返回对象的引用,在线程结束后将Object通过泛型转换回原来的类型就可以了。

这些只是我个人见解,如有不对还请见谅。