1. 程式人生 > >java執行緒池執行有返回值執行緒原始碼詳解

java執行緒池執行有返回值執行緒原始碼詳解

java執行緒池提供了幾種執行執行緒的方式,這裡主要討論關於執行有返回值的執行緒的實現原理

方式一:

使用方式:

ExecutorService executorService = Executors.newSingleThreadExecutor();
Future future = executorService.submit(new impleCallable());
String sss = (String) future.get();
System.out.println(sss);
public class impleCallable implements
Callable{
@Override public Object call() throws Exception { return "我是實現了Callable的一個執行緒"; } }

輸出:

我是實現了Callable的一個執行緒

原始碼:

下面看呼叫的submit方法

public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        execute(ftask);
        return
ftask; }
 protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
        return new FutureTask<T>(callable);
 }

可以看到是把我們實現了Callabe的物件封裝成了一個FutureTask物件,並且呼叫了執行緒池的execute()方法,咦。。這個方法不是我們平常把執行緒丟到執行緒池裡執行的方法嗎?為啥我們呼叫的是執行緒池的submit()方法最終是呼叫了execute()方法呢?這個FutureTask何許人也?下面來看。

public class FutureTask<V> implements RunnableFuture<V> {
    public void run() {
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                try {
                    result = c.call();
                } catch (Throwable ex) {
                }
                if (ran)
                    set(result);
            }
        }
    }
}
protected void set(V v) {
        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
            outcome = v;
        }
    }

可以看到這個FutureTask本身也是實現Runnable介面,也就是他也是一個執行緒,看他的run方法可以看到他最終呼叫的是我們submit(T)的時候傳過來的物件的call方法,並且把返回值賦值給result.然後呼叫set方法把result複製給outcome。至此,執行緒執行完畢,並且返回值也賦值給了outcome.那麼如何獲取這個outcome呢,下面我們看FutureTask的get()方法

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

可以看到,get方法就是把outcome給返回出去了。

方式二

使用方式

 ExecutorService executorService = Executors.newSingleThreadExecutor();
        Future future = executorService.submit(new impleRunable(),"我是一個實現了Runnable的執行緒");
        String sss = (String) future.get();
        System.out.println(sss);

輸出

我是一個實現了Runnable的執行緒

原始碼

下面看呼叫的submit方法

public <T> Future<T> submit(Runnable task, T result) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task, result);
        execute(ftask);
        return ftask;
    }
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
        return new FutureTask<T>(runnable, value);
    }
public FutureTask(Runnable runnable, V result) {
        this.callable = Executors.callable(runnable, result);
        this.state = NEW;       // ensure visibility of callable
    }
public static <T> Callable<T> callable(Runnable task, T result) {
        if (task == null)
            throw new NullPointerException();
        return new RunnableAdapter<T>(task, result);
    }
static final class RunnableAdapter<T> implements Callable<T> {
        final Runnable task;
        final T result;
        RunnableAdapter(Runnable task, T result) {
            this.task = task;
            this.result = result;
        }
        public T call() {
            task.run();
            return result;
        }
    }

可以看到與方式一不同的地方在於引數的不同,但是可以看到,最終都是把Runnable物件封裝成Callable物件的實現類RunnableAdapter,然後在call()中把我們傳進去的引數result ruturn出來。

總結:

兩種方式的背後實現其實是同一套,都是基於Callable,第二種方式會把傳進去的Runnable封裝成Callable方法,並且call中返回的是我們傳進去的result物件