ReentrantLock鎖原始碼淺析
定義
公平鎖:
公平鎖是指多個執行緒按照申請鎖的順序來獲取鎖,執行緒直接進入佇列中排隊,佇列中的第一個執行緒才能獲得鎖
公平鎖的優點是等待鎖的執行緒不會餓死。
缺點是整體吞吐效率相對非公平鎖要低,等待佇列中除第一個執行緒以外的所有執行緒都會阻塞,CPU喚醒阻塞執行緒的開銷比非公平鎖大
公平鎖
非公平鎖是多個執行緒加鎖時直接嘗試獲取鎖,獲取不到才會到等待佇列的隊尾等待,但如果此時鎖剛好可用,那麼該執行緒可以無需阻塞直接獲取到鎖,所以非公平鎖有可能出現後申請鎖的執行緒先獲取鎖的場景
非公平鎖的優點是可以減少喚起執行緒的開銷,整體的吞吐效率高,因為執行緒有機率不阻塞直接獲得鎖,CPU不必喚醒所有執行緒
缺點是處於等待佇列中的執行緒可能會餓死,或者等很久才會獲得鎖
ReentrantLock是實現Lock介面的一種鎖
定義了一個final型別的Sync
Sync使用AQS的state表示對鎖的持有次數
分為公平鎖和非公平鎖
呼叫Lock方法
lock方法,分為公平鎖和非公平鎖兩個版本
(1)非公平鎖
(2)CAS操作
compareAndSetState(expect,update);
如果當前狀態值等於預期值,則原子地將同步狀態設定為給定的更新值。 此操作具有易失性讀寫的記憶體語義。
引數:期望 - 期望值,更新 - 新值
返回:如果成功則為真。 假返回表示實際值不等於預期值。
如果預期值位0那麼設定為1
最終也是呼叫sun.misc.Unsafe相關的方法,這個方法的四個引數第一個表示操作的是那個物件,第二個表示操作物件欄位的偏移量,第三個是期望值,第四個是更新值
(3)volatile
state狀態是用volatile來修飾的
如果不使用volatile的時候,如果兩個執行緒thread1和thread2同時執行同一個方法來修改state為1,當thread把state從0變為1時,thread2沒有感知還以為state還是0,這樣也成功把0修改為1,這樣兩個執行緒都認為自己成功執行了獲取鎖的行為
volatile的功能:
a: 保證變數線上程之間的可見性 就是上面說的
b:禁止指令重排序 在編譯階段插入記憶體屏障,來特定禁止指令重排序
如果使用volatile,兩個執行緒thread1和thread2,當thread1寫會成功之後會讓其它執行緒中該變數的副本失效,把成功後的值刷回主記憶體,並重新從主存load新的,這樣一來thread2 expect=0,update=1就會失敗,因為此時的expect=0是不成立的
JMM模型
工作記憶體:
每個執行緒都有自己的工作記憶體,裡面儲存了用到的變數和主記憶體的拷貝,叫做工作記憶體
執行緒對變數進行操作都在這個拷貝中操作,而不能直接讀寫主記憶體中的變數,每個執行緒的工作記憶體都是獨立的,執行緒操作資料只能在工作記憶體(虛擬機器棧)中進行,然後刷回到主存(堆加方法區)。這是 Java 記憶體模型定義的執行緒基本工作方式
當一個執行緒修改共享變數的值,其他執行緒能夠立即知道被修改了,Java是利用volatile關鍵字來提供可見性的。當變數被volatile修飾時,這個變數被修改後會立刻重新整理到主記憶體,當其它執行緒需要讀取該變數時,會去主記憶體中讀取新值。而普通變數則不能保證這一點
非公平鎖的流程因此在非公平鎖中,AQS的volatile int state +1表示獲取到了鎖
通過CAS設定AQS的成員status,大家注意到status是用volatile來修飾的,它在此處表示讓所執行緒能夠獲取到最新更改的值
設定當前擁有獨佔訪問許可權的執行緒。
引數:Thread.curretThread()當前執行緒
執行緒 - 所有者執行緒
執行完lock方法後,呼叫tryAcquire方法
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
獲取當前執行緒,拿到當前鎖狀態
如果沒加鎖就加鎖,如果加了鎖,把當前鎖狀態state+1
若上述執行完成則代表成功,否則失敗
舉例分析兩個執行緒thread1和thread2進入方法,通過CAS方法進行爭搶鎖,誰能成功設把state從0設定為1,誰就能夠把鎖的獨佔執行緒設為自己。獲取到鎖的執行緒退出方法,進入業務邏輯。
假設thread1獲取到鎖,在tryAcquire方法中,thread1如果又重入這把鎖,那麼會將state+1
未獲取到鎖的thread2會通過else方法進入acquire方法中。然後進入tryAcquire方法,thread2未爭搶到鎖的執行緒進入acquire(1),因為thread1持有鎖,那麼本次tryAcquire返回false,進入addWaiter方法,這個方法是有一個FIFO的雙向連結串列,進入連結串列後的執行緒是等待執行緒,waitStatus表示節點的狀態,裡面的結點入隊之後可以自旋獲取鎖,自旋如果成功會將結點頭從等待佇列中摘除,thread2獲取到鎖,thread2執行業務邏輯。否則thread2一直會嘗試獲取鎖,失敗了返回false,直到成功了就返回true
公平鎖與非公平鎖的區別是,非公平鎖先通過CAS來搶佔鎖,然後在申請獲得鎖
而公平鎖直接申請獲得鎖
以獨佔模式獲取,忽略中斷。 通過至少呼叫一次 tryAcquire 實現,成功返回。 否則執行緒會排隊,可能會反覆阻塞和解除阻塞,呼叫 tryAcquire 直到成功。 此方法可用於實現方法 Lock.lock
它是ReentrantLock成員Sync的整個鎖的邏輯
tryAcquire方法是執行緒嘗試以獨佔模式獲取這個鎖。如果允許則獲取它。
acquireQueued方法是以獨佔不間斷模式獲取已在佇列中的執行緒,如果在等待時出現中斷,則會返回true,沒有中斷則返回false
如果執行緒無法獨佔模式獲取鎖,並且在等待時出現中斷,那麼中斷當前執行緒
公平鎖
首先獲得當前執行緒current
拿到狀態
公平鎖先判斷佇列(雙向連結串列)為空(head==tail)在進行cas搶佔,最終兩者為獲取鎖的執行緒都會進入到佇列中
因此,公平鎖就是保障了多執行緒下各執行緒獲取鎖的順序,先到的執行緒優先獲得鎖,後到的執行緒進入阻塞佇列
相關推薦
ReentrantLock鎖原始碼淺析
定義 公平鎖: 公平鎖是指多個執行緒按照申請鎖的順序來獲取鎖,執行緒直接進入佇列中排隊,佇列中的第一個執行緒才能獲得鎖
ReentrantLock鎖原始碼分析:非公平鎖
ReentrantLock是實現Lock介面的一種鎖 定義了一個final型別的Sync Sync使用AQS的state表示對鎖的持有次數
深入剖析ReentrantLock公平鎖與非公平鎖原始碼實現
原文地址: blog.csdn.net/lsgqjh/arti… ReentrantLock是JUC包中重要的併發工具之一,支援中斷和超時、還支援嘗試機制獲取鎖, 並且是一種通過程式設計控制的可重入鎖,儘可能減少死鎖問題。本文以公平與非公平鎖的
原始碼淺析 - CocoaLumberjack 3.6 之 DDLog
介紹 CocoaLumberjack is a fast & simple,yet powerful & flexible logging framework for Mac and iOS.
redis分散式鎖原始碼分析
更多原始碼分析已釋出到https://github.com/Zhucola/php_frameworks_analysis 目錄 單機模式下的redis鎖
EurekaClient 原始碼淺析
背景:最近在研究springCloud,對服務註冊中心也非常好奇,然後就看了一下原始碼,而且以後面試也需要了解一下,因此記錄一下
MySQL多版本併發控制機制(MVCC)-原始碼淺析
MySQL多版本併發控制機制(MVCC)-原始碼淺析 前言 作為一個數據庫愛好者,自己動手寫過簡單的SQL解析器以及儲存引擎,但感覺還是不夠過癮。<<事務處理-概念與技術>>誠然講的非常透徹,但只能提綱挈領,不
NavigableSet介面原始碼淺析(基於jdk1.8.0_231)
1. NavigableSet介面簡介 根據“實現了啥介面,提供啥服務”原則,若類實現了NavigableSet介面,說明該類可以可以根據給定的搜尋目標,返回一個匹配簇,舉例通俗不嚴格地講,對於一個集合類若實現了NavigableSet介面
HashTable原始碼淺析(基於jdk1.8.0_231)
HashTable 簡介 HashTable資料結構也是雜湊表(或稱散列表),基本與HashMap型別,不同的是,HashTable的key value 都不可為空,且是執行緒安全的;
Bytom側鏈Vapor原始碼淺析-節點出塊過程
在這篇文章中,作者將從Vapor節點的建立開始,進而拓展講解Vapor節點出塊過程中所涉及的原始碼。
StringBuilder原始碼淺析(基於jdk1.8.0_231)
StringBuilder 簡介 StringBuild API StringBuild 原始碼淺析 package java.lang; /** * A mutable sequence of characters.This class provides an API compatible
StringBuffer原始碼淺析(基於jdk1.8,0_231)
StringBuffer簡介 StringBufferjich 類似於String類,但StringBuffer是執行緒安全的可變字串類;
ReentrantLock AQS原始碼
前言 之前講過synchronized關鍵字在JDK1.7之前是一把重量級的鎖,那時JVM還未對synchronized關鍵字進行優化,所以synchronized會呼叫作業系統的函式實現加鎖和解鎖。而在JDK1.7後JVM對其進行優化,synchroni
AtomicLong原始碼淺析(基於jdk1.8.0_231)
AtomicLong 簡介 在32位作業系統中,64位的long 和 double 變數由於會被JVM當作兩個分離的32位來進行操作,所以不具有原子性。而AtomicLong能讓long的加1,減1操作,設定新值等操作在多執行緒中保持原子性;
【QT】 QThread部分原始碼淺析
本文章挑出QThread原始碼中部分重點程式碼來說明QThread啟動到結束的過程是怎麼排程的。其次因為到了Qt4.4版本,Qt的多執行緒就有所變化,所以本章會以Qt4.0.1和Qt5.6.2版本的原始碼來進行淺析。
原始碼淺析:MySQL一條insert操作,會寫哪些檔案?包括UNDO相關的檔案嗎?
DML操作的大致流程 在解答上述疑惑之前,我們來梳理一下DML操作的大致流程:
ReentrantLock鎖-CAS與阻塞
ReentrantLock鎖 ReentrantLock通過原子操作和阻塞實現鎖原理,一般使用lock獲取鎖,unlock釋放鎖
AQS原始碼淺析
一、AQS簡介 AbstractQueuedSynchronizer 抽象佇列同步器。簡稱AQS,同時擁有 同步佇列 與 等待佇列
詳解Java中的ReentrantLock鎖
ReentrantLock鎖 ReentrantLock是Java中常用的鎖,屬於樂觀鎖型別,多執行緒併發情況下。能保證共享資料安全性,執行緒間有序性
golang int切片排序_Golang之 sort 排序原始碼淺析
技術標籤:golang int切片排序 點選上方藍色 “鐵匠學程式設計” 關注我,讓我們一起學習!