Java Callable Future介面執行機制解密__Java

來源:互聯網
上載者:User

在Java中,我們執行非同步任務的代碼可以這麼寫。


 ExecutorService executorService = Executors.newSingleThreadExecutor();        Future<String> stringFuture = executorService.submit(() -> {            System.out.println("你好,世界");            return "helloworld";        });        System.out.println(stringFuture.getClass().getName());        System.out.println(stringFuture.get());

在submit方法中傳入一個callable介面對象。裡面承載的就是非同步執行的Java代碼。 我們可以看到非同步執行的任務很簡單,列印一行話 你好,世界。然後將helloworld字串返回給Future<T>介面對象接受執行的結果。當我們執行   stringFuture.get()方法的時候,如果非同步任務還沒有執行完。那麼future.get()方法所在的線程是會阻塞的。

像我們平常自己起一個線程去執行,執行的結果一般是那不會來的。但是Callable介面和Future介面這兩個介面卻可以做到將線程執行完的計算結果給拿到。

所以帶著這樣一個問題我們去查看下jdk的源碼是怎樣實現的。

首先第一行代碼

 ExecutorService executorService = Executors.newSingleThreadExecutor();
我們可以知道,建立了一個線程池。具體的代碼是這樣的。
 
 
public static ExecutorService newSingleThreadExecutor() {    return new FinalizableDelegatedExecutorService        (new ThreadPoolExecutor(1, 1,                                0L, TimeUnit.MILLISECONDS,                                new LinkedBlockingQueue<Runnable>()));}
Executors類建立了一個ExecutorService介面的實作類別。
 
 
該類的繼承結構是這樣的。
 
其中建立的ExecutorService介面的實作類別主要使用的是DelegatedExecutorService這個類。該類中封裝又封裝了一個ExecutorService介面的實作類別。
 
static class DelegatedExecutorService extends AbstractExecutorService {    private final ExecutorService e;    DelegatedExecutorService(ExecutorService executor) { e = executor; }    public void execute(Runnable command) { e.execute(command); }    public void shutdown() { e.shutdown(); }    public List<Runnable> shutdownNow() { return e.shutdownNow(); }    public boolean isShutdown() { return e.isShutdown(); }    public boolean isTerminated() { return e.isTerminated(); }    public boolean awaitTermination(long timeout, TimeUnit unit)        throws InterruptedException {        return e.awaitTermination(timeout, unit);    }    public Future<?> submit(Runnable task) {        return e.submit(task);    }    public <T> Future<T> submit(Callable<T> task) {        return e.submit(task);    }    public <T> Future<T> submit(Runnable task, T result) {        return e.submit(task, result);    }    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)        throws InterruptedException {        return e.invokeAll(tasks);    }    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,                                         long timeout, TimeUnit unit)        throws InterruptedException {        return e.invokeAll(tasks, timeout, unit);    }    public <T> T invokeAny(Collection<? extends Callable<T>> tasks)        throws InterruptedException, ExecutionException {        return e.invokeAny(tasks);    }    public <T> T invokeAny(Collection<? extends Callable<T>> tasks,                           long timeout, TimeUnit unit)        throws InterruptedException, ExecutionException, TimeoutException {        return e.invokeAny(tasks, timeout, unit);    }}
 
 我們可以看到,該類的所有的方法實現全都是調用可內部封裝的ExecutorService介面的實作類別。 
 
有讀者可能會問了,這個被封裝的介面的類是哪個類。這裡應該是ThreadPoolExecutor這個類。
我們可以看下整合關係圖
 
ThraedPoolExecutor類也是繼承了AbstractExecutorService這個類。這就好分析了。
接下來我們分析下面的代碼。
以後筆者直接將分析的內容以註解的形式寫在代碼旁邊
 
Future<String> stringFuture = executorService.submit(() -> {    System.out.println("你好,世界");    return "helloworld";});
 
 
public <T> Future<T> submit(Callable<T> task) {    if (task == null) throw new NullPointerException();
//實際上這裡是new了一個FutureTask類的對象。
//FutureTask類實現了Runnable,Future<T>和RunnableFuture<V>三個介面,說明之後返回的FutureTask類對象可以
//當做Future<T>介面的實作類別來用    RunnableFuture<T> ftask = newTaskFor(task);
//Callable<T>介面裡的非同步代碼是在這行代碼被調用的。
//execute方法接收了剛才那個FutureTask類的對象做為參數去執行。我們到這個execute()方法裡去看看    execute(ftask);    return ftask;}


 
我們可以看到該方法實現在ThreadPoolExecutor類裡面。當然execute(Runnable r)這個方法是聲明在Executor介面裡面的。
好,我們到execute()方法的實現裡面去分析分析
 
public void execute(Runnable command) {    if (command == null)        throw new NullPointerException();    /*     * Proceed in 3 steps:     *     * 1. If fewer than corePoolSize threads are running, try to     * start a new thread with the given command as its first     * task.  The call to addWorker atomically checks runState and     * workerCount, and so prevents false alarms that would add     * threads when it shouldn't, by returning false.     *     * 2. If a task can be successfully queued, then we still need     * to double-check whether we should have added a thread     * (because existing ones died since last checking) or that     * the pool shut down since entry into this method. So we     * recheck state and if necessary roll back the enqueuing if     * stopped, or start a new thread if there are none.     *     * 3. If we cannot queue task, then we try to add a new     * thread.  If it fails, we know we are shut down or saturated     * and so reject the task.     */    int c = ctl.get();    if (workerCountOf(c) < corePoolSize) {
//我們點入到這行代碼裡面去,其他的太複雜了,筆者這裡就先不分析了,因為與今天的主題不是太相關        if (addWorker(command, true))            return;        c = ctl.get();    }    if (isRunning(c) && workQueue.offer(command)) {        int recheck = ctl.get();        if (! isRunning(recheck) && remove(command))            reject(command);        else if (workerCountOf(recheck) == 0)            addWorker(null, false);    }    else if (!addWorker(command, false))        reject(command);}

 
//這個方法的形參就是剛才new出來的FutureTask類的對象。因為其也實現了Runnable介面,所以可以這樣傳遞
 
private boolean addWorker(Runnable firstTask, boolean core) {    retry:    for (;;) {        int c = ctl.get();        int rs = runStateOf(c);        // Check if queue empty only if necessary.        if (rs >= SHUTDOWN &&            ! (rs == SHUTDOWN &&               firstTask == null &&               ! workQueue.isEmpty()))            return false;        for (;;) {            int wc = workerCountOf(c);            if (wc >= CAPACITY ||                wc >= (core ? corePoolSize : maximumPoolSize))                return false;            if (compareAndIncrementWorkerCount(c))                break retry;            c = ctl.get();  // Re-read ctl            if (runStateOf(c) != rs)                continue retry;            // else CAS failed due to workerCount change; retry inner loop        }    }    boolean workerStarted = false;    boolean workerAdded = false;    Worker w = null;    try {        w = new Worker(firstTask);        final Thread t = w.thread;        if (t != null) {            final ReentrantLock mainLock = this.mainLock;            mainLock.lock();            try {                // Recheck while holding lock.                // Back out on ThreadFactory failure or if                // shut down before lock acquired.                int rs = runStateOf(ctl.get());                if (rs < SHUTDOWN ||                    (rs == SHUTDOWN && firstTask == null)) {                    if (t.isAlive()) // precheck that t is startable                        throw new IllegalThreadStateException();                    workers.add(w);                    int s = workers.size();                    if (s > largestPoolSize)                        largestPoolSize = s;                    workerAdded = true;                }            } finally {                mainLock.unlock();            }            if (workerAdded) {
//這行代碼啟動了Callable介面裡的線程代碼。
//既然線程被啟動了,裡面我們就要去看看Runnable介面定義的run方法是如何?的,我們進入到FutureTask類的Run方法實作類別中去                t.start();                workerStarted = true;            }        }    } finally {        if (! workerStarted)            addWorkerFailed(w);    }    return workerStarted;}

 
 
 
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 {
//這行代碼調用了Callable介面實作類別的call方法。得到的傳回值會返回給一個result變數
//下面的代碼將這個變數設定到FutureTask對象的成員變數outcome上。                result = c.call();                ran = true;            } catch (Throwable ex) {                result = null;                ran = false;                setException(ex);            }            if (ran)
//就是這行代碼將Callable介面的call方法的執行結果設定到FutureTask類對象的outcome成員變數上
//我們可以點進入看一下是如何?的                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);    }}

 
 
protected void set(V v) {    if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
//將Callable介面的call方法的計算結果放置到outcome變數上。        outcome = v;        UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state        finishCompletion();    }}

 
 
到這裡我們可以知道,執行完的結果是儲存在FutureTask類對象的outcome成員變數上的。
我們再去看下Future<T>介面定義的get方法
 
/** * @throws CancellationException {@inheritDoc} */public V get() throws InterruptedException, ExecutionException {    int s = state;    if (s <= COMPLETING)        s = awaitDone(false, 0L);
//發現這裡有個report方法,點進去看一下    return report(s);}
 
@SuppressWarnings("unchecked")private V report(int s) throws ExecutionException {
//我們可以發現果然拿的是outcome成員變數的值    Object x = outcome;    if (s == NORMAL)        return (V)x;    if (s >= CANCELLED)        throw new CancellationException();    throw new ExecutionException((Throwable)x);}

到此文章的結束了
 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.