Java常見的鎖總結(可重入鎖、樂觀鎖、悲觀鎖、公平鎖、非公平鎖、自旋鎖、偏向鎖、分段鎖等)


Java常見的鎖總結

Java常見的鎖總結
鎖是一種多線程同步訪問技術。
我們常聽到的關於鎖的詞有:排它鎖、共享鎖、可重入鎖、樂觀鎖、悲觀鎖、公平鎖、非公平鎖、自旋鎖、偏向鎖、輕量級鎖、重量級鎖、分段鎖等。這些大多是對鎖進行類型划分,或者是一種鎖的設計思想,彼此之間很多性質有的是兼容的,有的是對立的。
我們常用的Java中的鎖有:CAS機制、synchronized、ReentrantLock、ReentrantReadWriteLock

根據鎖的性質分類
根據重入和排它性分析:共享鎖、可重入鎖、排它鎖
共享鎖:線程可以同時獲取鎖。ReentrantReadWriteLock對於讀鎖是共享的。在讀多寫少的情況下使用共享鎖會非常高效。
重入鎖:線程獲取鎖后可以重復執行鎖區域。Java提供的鎖都是可重入鎖。不可重入鎖非常容易導致死鎖。
排它鎖:多線程不可同時獲取的鎖,與共享鎖對立。與重入鎖不矛盾可以是並存屬性。

根據獲取鎖的方式:樂觀鎖、悲觀鎖
樂觀鎖:其實是一種采用具有原子性的CAS非加鎖機制,保證當前線程原子性執行。
悲觀鎖:直接加鎖進行線程隔離。synchronized、ReentrantLock、ReentrantReadWriteLock的寫鎖都屬於悲觀鎖
悲觀鎖適合寫操作非常多的場景,樂觀鎖適合讀操作非常多的場景,不加鎖會帶來大量的性能提升。

根據獲取鎖時是否先參與排隊:公平鎖、非公平鎖
公平鎖:線程試圖獲取鎖時,先按嘗試獲取鎖的時間順序排隊
非公平鎖:線程試圖獲取鎖時,如果當前鎖沒有線程占有,則跟排隊獲取鎖的線程一起競爭鎖而無序按順序排隊,則為非公平鎖。如果競選失敗,依然要排隊。
非公平鎖比較高效,因為公平鎖需要有先線程喚起

根據鎖的狀態划分:偏向鎖、輕量級鎖、重量級鎖
偏向鎖:一段同步代碼一直被一個線程所訪問,那么該線程會自動獲取鎖。降低獲取鎖的代價。類似於樂觀鎖。
輕量級鎖:當鎖是偏向鎖的時候,被另一個線程所訪問,偏向鎖就會升級為輕量級鎖,其他線程會通過自旋的形式嘗試獲取鎖,不會阻塞,提高性能
重量級鎖:當鎖為輕量級鎖的時候,另一個線程雖然是自旋,但自旋不會一直持續下去,當自旋一定次數的時候,還沒有獲取到鎖,就會進入阻塞,該鎖膨脹為重量級鎖。重量級鎖會讓其他申請的線程進入阻塞,性能降低。

根據鎖粒度划分:分段鎖等
分段鎖:分段鎖是一種鎖思想,對數據分段加鎖已提高並發效率,比如jdk8之前的ConcurrentHashMap,jdk8后采用CAS+synchronized。當需要put元素的時候,並不是對整個hashmap進行加鎖,而是先通過hashcode來知道他要放在哪一個分段中,然后對這個分段進行加鎖,所以當多線程put的時候,只要不是放在一個分段中,就實現了真正的並行的插入。
  但是,在統計size的時候,可就是獲取hashmap全局信息的時候,就需要獲取所有的分段鎖才能統計。
  分段鎖的設計目的是細化鎖的粒度,當操作不需要更新整個數組的時候,就僅僅針對數組中的一項進行加鎖操作。
synchronized在靜態方法上時,鎖定的是這個類信息,又稱為類鎖。
synchronized在普通方法上時,鎖定的是這個對象實例,又稱為對象鎖。
synchronized在代碼塊上時,鎖定的是括號里的對象。

鎖消除
JVM會加鎖的代碼進行逃逸分析,當發現是單線程時,會去掉代碼所加的鎖,以達到優化。

關於鎖要知道的事情
AQS(AbstractQueuedSynchronizer 抽象隊列式的同步器)是一種多線程訪問共享資源的同步器框架。許多同步類實現都依賴於它,如常用的ReentrantLock/Semaphore/CountDownLatch…
CAS(Compare and Swap 比較並交換)是樂觀鎖技術。底層事Java的sun.misc.Unsafe類,它可以直接操作內存。
獲取鎖和釋放鎖都是有資源消耗的,線程的阻塞和喚起也要消耗資源。如果要阻塞或喚醒一個線程就需要操作系統介入,需要在戶態與核心態之間切換,這種切換會消耗大量的系統資源,因為用戶態與內核態都有各自專用的內存空間,專用的寄存器等。所以CAS在並發碰撞少的情況下會優於獲取鎖。
synchronized是JVM層次實現的,在高並發的情況下性能不如代碼層次實現的Lock高效,但是synchronized一直在被優化,現在差距已經不大了,是官方推薦的方式。


免責聲明!

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



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