當緩存中沒有要找的數據時,則要從數據庫中去查詢,而當併發量比較大時可能會擊穿數據庫,因此guava cache對同一值的查詢作了合併請求的處理。其中就用到了SettableFuture,相似一把鎖,只會讓一個請求線程去查詢數據庫而其餘查詢請求線程(查詢同一個值)會處於等待狀態。 下面是google guava 18.0中SettableFuture的UML關係圖:數據庫
從圖中咱們能夠看到SettableFuture實現了Future接口,說明能夠異步的獲取結果。它主要的實現繼承於AbstractFuture,而SettableFuture只是作了一層封裝。下面主要分析AbstractFuture。 AbstractFuture包含兩個屬性:一個是內部類Sync對象,一個是ExecutionList對象。 1.ExecutionList 緩存
ExecutionList從字面意思理解就是包含一系列execution的list,看ExecutionList的類圖可知,它有一個內部類RunnableExecutorPair表示單向列表list中的一個節點,該節點由Runnable,Executor和next節點構成,當ExecutionList執行execution的時候,先判斷executed是否已經執行過,若是沒有爲了按照順序執行任務首先會反轉單向鏈表,而後纔是executor.execute(runnable)。併發
2.Sync 異步
Sync也是繼承AQS,實現對線程併發的控制。Sync包含5種狀態(運行中:0,完成中:1,已完成:2,已取消:4,已中斷:8),存儲的值和異常。AbstractFuture相似一把共享鎖,某一個時刻只能有一個線程可以擁有AQS的state進行寫操做,而讀的時候則能夠讓多個線程同時讀。Sync中的set, setException和cancel操做都是寫操做。SettableFuture中調用set的過程是這樣的:當有一個線程調用set操做或setException時,其餘寫線程只能進入同步隊列中進行等待,而其餘讀線程會根據Sync當前的狀態返回對應的結果。並且AQS的state初始值是0,無論是set,setException和cancel操做後,state的值都不會爲再爲0,而是各個操做後的狀態值。若是同時有多個線程訪問,只有一個線程的操做會被接受,其餘線程只有等待擁有鎖的線程完成該操做,並獲取那個操做的結果。google