由FutureTask的get方法靠什么機制來阻塞引發的思考


1. FutureTask的get方法靠什么機制來阻塞

看其get方法源碼:

/**
     * @throws CancellationException {@inheritDoc}
     */
    public V get() throws InterruptedException, ExecutionException {
        return sync.innerGet();
    }

不難發現,FutureTask是依靠其內部類java.util.concurrent.FutureTask.Sync<V>類來實現阻塞。

Sync又是實現了AbstractQueuedSynchronizer類。

private final class Sync extends AbstractQueuedSynchronizer

看都有誰實現了這個類:

dza5vly3.q4n

里面有很多我們平時用到的,但是不怎么清楚其原理的類,原來都是靠實現AbstractQueuedSynchronizer來達到相應的同步機制。

AbstractQueuedSynchronizer又是靠什么來實現阻塞以及維持協調好各競爭線程間的資源分配的?看下一段。

2. 分析AbstractQueuedSynchronizer

從上面分析來看AbstractQueuedSynchronizer應該是JDK的concurrent包里比較重要的一個機制。用google先了解下他的面貌:

image

中文的blog的搜索結果說明有很多人對這個做了總結與學習,最下面框起來的一個pdf結果應該是對這個的一個論文。

英文原文

中文版

論文中闡述了幾點比較關鍵的地方

1. 方法命名的問題

同步器一般包含兩種方法,一種是acquire,另一種是release。acquire操作阻塞調用的線程,直到或除非同步狀態允許其繼續執行。而release操作則是通過某種方式改變同步狀態,使得一或多個被acquire阻塞的線程繼續執行。

j.u.c包中並沒有對同步器的API做一個統一的定義。因此,有一些類定義了通用的接口(如Lock),而另外一些則定義了其專有的版本。因此在不同的 類中,acquire和release操作的名字和形式會各有不同。例 如:Lock.lock,Semaphore.acquire,CountDownLatch.await和FutureTask.get,在這個框架 里,這些方法都是acquire操作。但是,J.U.C為支持一系列常見的使用選項,在類間都有個一致約定。在有意義的情況下,每一個同步器都支持下面的 操作:

阻塞和非阻塞(例如tryLock)同步。
可選的超時設置,讓調用者可以放棄等待
通過中斷實現的任務取消,通常是分為兩個版本,一個acquire可取消,而另一個不可以。

2. 實現同步器的三個“組件”

為了實現上述操作,需要下面三個基本組件的相互協作:

a)  同步狀態的原子性管理;
b) 線程的阻塞與解除阻塞;
c) 隊列的管理;

怎么實現這三個部件,論文中有詳細介紹。

論文中提到“整個框架的關鍵就是如何管理被阻塞的線程的隊列”也就是對應上面三個“組件”的c部分。

AQS中使用了CLH隊列。

為什么采用CLH而不是MCS,因為CLH更容易實現取消與超時機制。

3. CLH隊列

CLH鎖簡明介紹

談CLH隊列時,前面要先談很多基礎知識,不然直接閱讀上面的簡明介紹,會有點坡度。

 

4. AQS思維導圖

2016-11-30 09-24-56_XMind - D__600.self_05.code_04.java_21.JDK1.6_src_study_21.JDK1.6_src_study_docu

2016-11-30 09-21-50_XMind - D__600.self_05.code_04.java_21.JDK1.6_src_study_21.JDK1.6_src_study_docu

 

5. FutureTask思維導圖

2016-11-30 09-22-12_XMind - D__600.self_05.code_04.java_21.JDK1.6_src_study_21.JDK1.6_src_study_docu


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM