多執行緒鎖的分類和概述

2022-03-06 21:54:45 字數 1741 閱讀 5674

一般樂觀鎖和悲觀鎖都是在資料庫層面的。

公平和非公平鎖是根據執行緒的搶占機制來分的,如果是公平鎖,則執行緒獲取鎖的順序是按照執行緒請求鎖的時間早晚來決定的,來的晚的進阻塞佇列,可以把公平鎖理解成排隊,而非公平鎖則是大家一起搶,不管你先來後到,誰搶到了算誰的,可以理解成平時咱們擠公交和擠地鐵。

reentrantlock則提供了公平和非公平鎖的實現。說的具體一點就是。如果有三個執行緒1,2,3,此時執行緒1持有了鎖,2,3執行緒也都需要獲取這把鎖,並且2請求比3早,如果是公平鎖,那就是2執行緒獲取,3執行緒先一邊待著去,等2用完了他才能用。非公平鎖就是,2,3的機會都是一樣的,你們倆根據執行緒排程策略,誰搶著算誰的。

一般在沒有非常需要公平鎖的前提下做好使用非公平,因為公平鎖的排列方式會帶來額外的效能開銷。

可重入,顧名思義就是可以反覆的進入,放到乙個執行緒當中,當乙個執行緒想要獲取乙個被其他執行緒已經取得的互斥鎖的時候,毫無疑問會被阻塞。但是如果乙個執行緒再次獲取他已經持有的鎖的時會不會阻塞呢?

舉個具體的例子:

/**

* 測試可重入鎖

*/public class resyncdemo catch (interruptedexception e)

}public synchronized void m2()

public static void main(string args) ).start();

new thread(() -> ).start();

}}

輸出結果

i am m1

i am m2

i am m2

執行上面的**,可以觀察到 第乙個 i am m1和m2幾乎是同時輸出的。而第二個i am m2卻是在兩秒後輸出的。這一點就可以印證synchronized是可重入鎖。因為我們知道,synchronized鎖的是物件,當執行緒1進入m1方法的時候。執行第乙個列印,當他執行到呼叫m2方法的時候,發現是m2是需要持有鎖才能訪問,但是這個鎖已經被自己持有了,就是當前物件的鎖。於是可以直接呼叫。呼叫完畢之後然後休眠兩秒。等待程式結束,執行緒2才可以去執行。

關於可重入鎖的原理其實是這樣的,在鎖內部維護乙個執行緒的標誌,用來標識該鎖是被哪個執行緒持有的。然後關聯乙個計數器,當計數器為0的時候,代表該鎖沒有被任何執行緒占用。當乙個執行緒獲取了鎖的時候,計數器會變成1.然後其他執行緒再來的時候,會發現這個鎖已經被其他執行緒持有了,並且比較這個鎖不是自己持有的,於是阻塞掛起。

但是獲取了該鎖的執行緒,再次訪問同步方法的時候,例如上面的m1呼叫m2,跟執行緒標誌比較一下發現這個鎖的擁有者是自己。於是就可以直接進入,然後把count+1,釋放之後-1,直到計數器為0的時候,代表執行緒不管重入了多少次,現在都已經全部釋放了。然後把執行緒的標識置為null,然後其他被阻塞的執行緒就會來搶這個鎖

關於自旋鎖,關於自旋鎖其實很多地方都用到了。cas就是一種自旋鎖,在synchronized的鎖公升級過程,aqs中也用到了自旋鎖。在很多鎖中,乙個執行緒獲取鎖失敗後,一般都會被阻塞而被掛起。等到執行緒獲取鎖的時候,又要把執行緒喚醒。這種反覆的切換開銷比較大,於是就出現了自旋鎖,自旋鎖嚴格意義上來說不是鎖,或者說是一種非阻塞的「鎖」,自旋鎖的過程是這樣的,當前執行緒獲取鎖的時候,如果發現這個鎖被其他的執行緒占有,在不放棄cpu使用權的情況下,多次嘗試獲取(預設是十次,可以更改)。自旋鎖認為,自己在這十次獲取的過程中,其他執行緒已經釋放了鎖。如果指定的次數還沒有獲取到,當前執行緒才會被阻塞掛起。所以自旋鎖是一種用cpu時間換執行緒阻塞和排程的開銷。但是造成的問題是,如果指定的次數還沒有獲取到,這些cpu時間可能會被白白浪費,所以要根據實際情況使用。

多執行緒鎖的分類說明

synchronized 可重入 重型鎖 鎖公升級 volatile 可見,禁止指令重排 atomic integer reetrantlock countdownlatch 倒數等待執行緒計數器,倒計數器為0時執行緒執行。cyclicbarrier 滿員執行緒執行。marriage phar 階段...

Oracle 鎖(概述 分類)

加鎖是實現資料庫併發控制的乙個非常重要的技術。當事務在對某個資料物件進行操作前,先向系統發出請求,對其加鎖。加鎖後事務就對該資料物件有了一定的控制,在該事務釋放鎖之前,其他的事務不能對此資料物件進行更新操作。oracle通過使用鎖 lock 機制維護資料的完整性 併發性和一致性。oracle在兩個不...

0623 多執行緒和鎖

多執行緒和鎖 當 std condition variable 物件的某個 wait 函式被呼叫的時候,它使用 std unique lock 通過 std mutex 來鎖住當前執行緒。當前執行緒會一直被阻塞,直到另外乙個執行緒在相同的 std condition variable 物件上呼叫了 ...