Java併發包原始碼學習之AQS框架(二)CLH lock queue和自旋鎖
上一篇文章提到AQS是基於CLH lock queue
,那麼什麼是CLH lock queue,說複雜很複雜說簡單也簡單, 所謂大道至簡:
CLH lock queue其實就是一個FIFO的佇列,佇列中的每個結點(執行緒)只要等待其前繼釋放鎖就可以了。
AbstractQueuedSynchronizer
是通過一個內部類Node
來實現CLH lock queue的一個變種,但基本原理是類似的。
在介紹Node
類之前,我們來介紹下Spin Lock
,通常就是用CLH lock queue
來實現自旋鎖,所謂自旋鎖簡單來說就是執行緒通過迴圈來等待而不是睡眠。 Talk 再多不如 show code:
class ClhSpinLock { private final ThreadLocal<Node> prev; private final ThreadLocal<Node> node; private final AtomicReference<Node> tail = new AtomicReference<Node>(new Node()); public ClhSpinLock() { this.node = new ThreadLocal<Node>() {protected Node initialValue() { return new Node(); } }; this.prev = new ThreadLocal<Node>() { protected Node initialValue() { return null; } }; } public void lock() { finalNode node = this.node.get(); node.locked = true; // 一個CAS操作即可將當前執行緒對應的節點加入到佇列中, // 並且同時獲得了前繼節點的引用,然後就是等待前繼釋放鎖 Node pred = this.tail.getAndSet(node); this.prev.set(pred); while (pred.locked) {// 進入自旋 } } public void unlock() { final Node node = this.node.get(); node.locked = false; this.node.set(this.prev.get()); } private static class Node { private volatile boolean locked; } }
上面的程式碼中執行緒巧妙的通過ThreadLocal
儲存了當前結點和前繼結點的引用,自旋就是lock中的while迴圈。 總的來說這種實現的好處是保證所有等待執行緒的公平競爭,而且沒有競爭同一個變數,因為每個執行緒只要等待自己的前繼釋放就好了。 而自旋的好處是執行緒不需要睡眠和喚醒,減小了系統呼叫的開銷。
public static void main(String[] args) { final ClhSpinLock lock = new ClhSpinLock(); lock.lock(); for (int i = 0; i < 10; i++) { new Thread(new Runnable() { @Override public void run() { lock.lock(); System.out.println(Thread.currentThread().getId() + " acquired the lock!"); lock.unlock(); } }).start(); Thread.sleep(100); } System.out.println("main thread unlock!"); lock.unlock(); }
上面程式碼的執行的結果應該跟上一篇文章中的完全一樣。
ClhSpinLock
的Node類實現很簡單隻有一個布林值,AbstractQueuedSynchronizer$Node
的實現稍微複雜點,大概是這樣的:
+------+ prev +-----+ +-----+ head | | <---- | | <---- | | tail +------+ +-----+ +-----+
- head:頭指標
- tail:尾指標
- prev:指向前繼的指標
- next:這個指標圖中沒有畫出來,它跟prev相反,指向後繼
關鍵不同就是next指標,這是因為AQS中執行緒不是一直在自旋的,而可能會反覆的睡眠和喚醒,這就需要前繼釋放鎖的時候通過next 指標找到其後繼將其喚醒,也就是AQS的等待佇列中後繼是被前繼喚醒的。AQS結合了自旋和睡眠/喚醒兩種方法的優點。
其中執行緒的睡眠和喚醒就是用到我下一篇文章將要講到的LockSupport
。
最後提一點,上面的ClhSpinLock
類中還有一個關鍵的點就是lock
方法中註釋的地方:
一個CAS操作即可將當前執行緒對應的節點加入到佇列中,並獲取到其前繼。
實際上可以說整個AQS框架都是建立在CAS的基礎上的,這些原子操作是多執行緒競爭的核心地帶,AQS中很多繞來繞去的程式碼都是為了 減少競爭。我會在後面AbstractQueuedSynchronizer
原始碼分析中做詳細介紹。
相關推薦
Java併發包原始碼學習之AQS框架(二)CLH lock queue和自旋鎖
上一篇文章提到AQS是基於CLH lock queue,那麼什麼是CLH lock queue,說複雜很複雜說簡單也簡單, 所謂大道至簡: CLH lock queue其實就是一個FIFO的佇列,佇列中的每個結點(執行緒)只要等待其前繼釋放鎖就可以了。 AbstractQueuedSynchronizer
Java併發包原始碼學習之AQS框架(四)AbstractQueuedSynchronizer原始碼分析
經過前面幾篇文章的鋪墊,今天我們終於要看看AQS的廬山真面目了,建議第一次看AbstractQueuedSynchronizer 類原始碼的朋友可以先看下我前面幾篇文章: 分析原始碼是非常枯燥乏味的一件事,其實程式碼本身其實就是最好的說明了,因此基本都是貼出一些程式碼加上一些註釋, 因為Abstract
Java併發包原始碼學習之AQS框架(一)概述
AQS其實就是java.util.concurrent.locks.AbstractQueuedSynchronizer這個類。 閱讀Java的併發包原始碼你會發現這個類是整個java.util.concurrent的核心之一,也可以說是閱讀整個併發包原始碼的一個突破口。 比如讀ReentrantLock的
Java併發包原始碼學習之執行緒池(一)ThreadPoolExecutor原始碼分析
Java中使用執行緒池技術一般都是使用Executors這個工廠類,它提供了非常簡單方法來建立各種型別的執行緒池: public static ExecutorService newFixedThreadPool(int nThreads) public static ExecutorService
JavaWeb學習之Hibernate框架(二)
utils xtend auto etl SQ dial begin 可選 oct hibernateAPI詳解 Configuration 創建 加載主配置 創建sessionFactory
Java併發包原始碼學習系列:AQS共享式與獨佔式獲取與釋放資源的區別
[toc] # Java併發包原始碼學習系列:AQS共享模式獲取與釋放資源 往期回顧: - [Java併發包原始碼學習系列:AbstractQueuedSynchronizer](https://www.cnblogs.com/summerday152/p/14238284.html) - [Java併
Java併發包原始碼學習系列:阻塞佇列實現之ArrayBlockingQueue原始碼解析
[toc] 系列傳送門: - [Java併發包原始碼學習系列:AbstractQueuedSynchronizer](https://blog.csdn.net/Sky_QiaoBa_Sum/article/details/112254373) - [Java併發包原始碼學習系列:CLH同步佇列及同步資源
Java併發包原始碼學習系列:阻塞佇列實現之LinkedBlockingQueue原始碼解析
[toc] 系列傳送門: - [Java併發包原始碼學習系列:AbstractQueuedSynchronizer](https://blog.csdn.net/Sky_QiaoBa_Sum/article/details/112254373) - [Java併發包原始碼學習系列:CLH同步佇列及同步資源
Java併發包原始碼學習系列:阻塞佇列實現之PriorityBlockingQueue原始碼解析
[toc] 系列傳送門: - [Java併發包原始碼學習系列:AbstractQueuedSynchronizer](https://blog.csdn.net/Sky_QiaoBa_Sum/article/details/112254373) - [Java併發包原始碼學習系列:CLH同步佇列及同步資源
Java併發包原始碼學習系列:阻塞佇列實現之DelayQueue原始碼解析
[toc] 系列傳送門: - [Java併發包原始碼學習系列:AbstractQueuedSynchronizer](https://blog.csdn.net/Sky_QiaoBa_Sum/article/details/112254373) - [Java併發包原始碼學習系列:CLH同步佇列及同步資源
Java併發包原始碼學習系列:阻塞佇列實現之SynchronousQueue原始碼解析
[toc] 系列傳送門: - [Java併發包原始碼學習系列:AbstractQueuedSynchronizer](https://blog.csdn.net/Sky_QiaoBa_Sum/article/details/112254373) - [Java併發包原始碼學習系列:CLH同步佇列及同步資源
Java併發包原始碼學習系列:阻塞佇列實現之LinkedTransferQueue原始碼解析
[toc] 系列傳送門: Java併發包原始碼學習系列:AbstractQueuedSynchronizer Java併發包原始碼學習系列:CLH同步佇列及同步資源獲取與釋放 Java併發包原始碼學習系列:AQS共享式與獨佔式獲取與釋放資源的區別 Java併發包原始碼學習系列:ReentrantLock可重
Java併發包原始碼學習系列:AbstractQueuedSynchronizer
[toc] > 本文基於JDK1.8 ## 本篇學習目標 - 瞭解AQS的設計思想以及重要欄位含義,如通過state欄位表示同步狀態等。 - 瞭解AQS內部維護鏈式雙向同步佇列的結構以及幾個重要指標。 - 瞭解五種重要的同步狀態。 - 明確兩種模式:共享模式和獨佔模式。 - 學習兩種模式下AQS提供的模
Java併發包原始碼學習系列:CLH同步佇列及同步資源獲取與釋放
[toc] ## 本篇學習目標 - 回顧CLH同步佇列的結構。 - 學習獨佔式資源獲取和釋放的流程。 ## CLH佇列的結構 我在[Java併發包原始碼學習系列:AbstractQueuedSynchronizer#同步佇列與Node節點](https://www.cnblogs.com/summer
Java併發包原始碼學習系列:掛起與喚醒執行緒LockSupport工具類
[toc] 系列傳送門: - [Java併發包原始碼學習系列:AbstractQueuedSynchronizer](https://blog.csdn.net/Sky_QiaoBa_Sum/article/details/112254373) - [Java併發包原始碼學習系列:CLH同步佇列及同步資源
Java併發包原始碼學習系列:JDK1.8的ConcurrentHashMap原始碼解析
[toc] 系列傳送門: - [Java併發包原始碼學習系列:AbstractQueuedSynchronizer](https://blog.csdn.net/Sky_QiaoBa_Sum/article/details/112254373) - [Java併發包原始碼學習系列:CLH同步佇列及同步資源
Java併發包原始碼學習系列:阻塞佇列BlockingQueue及實現原理分析
[toc] 系列傳送門: - [Java併發包原始碼學習系列:AbstractQueuedSynchronizer](https://blog.csdn.net/Sky_QiaoBa_Sum/article/details/112254373) - [Java併發包原始碼學習系列:CLH同步佇列及同步資源
Java併發包原始碼學習系列:基於CAS非阻塞併發佇列ConcurrentLinkedQueue原始碼解析
[toc] ## 非阻塞併發佇列ConcurrentLinkedQueue概述 我們之前花了很多時間瞭解學習BlockingQueue阻塞佇列介面下的各種實現,也大概對阻塞佇列的實現機制有了一定的瞭解:阻塞 + 佇列嘛。 而且其中絕大部分是完全基於獨佔鎖ReentrantLock和條件機制conditi
Java併發包原始碼學習系列:執行緒池ThreadPoolExecutor原始碼解析
[toc] 系列傳送門: - [Java併發包原始碼學習系列:AbstractQueuedSynchronizer](https://blog.csdn.net/Sky_QiaoBa_Sum/article/details/112254373) - [Java併發包原始碼學習系列:CLH同步佇列及同步資源
Java併發包原始碼學習系列:執行緒池ScheduledThreadPoolExecutor原始碼解析
[toc] ## ScheduledThreadPoolExecutor概述 我們在上一篇學習了ThreadPoolExecutor的實現原理:[Java併發包原始碼學習系列:執行緒池ThreadPoolExecutor原始碼解析](https://blog.csdn.net/Sky_QiaoBa_Sum