天天看點

java 互斥量_[轉]各種互斥量的總結

研究所學生階段一直使用C++,到工作時,才接觸到Java。寫了這麼多年的多線程程式,覺得對于互斥(注意,不是同步哦)的各種鎖有必要做個總結。

這裡我想将Windows,Linux和Java JVM三種環境中使用鎖的環境及雖然将Windows,Linux和Java JVM放在一起比較是有些不合适的,但是對基于Windows作業系統C++,Linux作業系統C++及Java程式而言,在應用層面上來說,這種橫向比較對于加深對于多線程互斥中鎖應用上的了解,是有意義的。如果有不正确的地方,歡迎指正。

Windows

有InterLock系列函數,CRITICAL_SECTION臨界區,SRWLock讀寫鎖,Mutex互斥量

Linux

有atomic_t,Mutex互斥量,,rwlock讀寫鎖

Java JVM

有Atomic原子操作,synchronized同步關鍵字,ReentrantLock,ReentrantReadWriteLock讀寫鎖

互斥量

環境

睡眠鎖 / 自旋鎖

可重入 / 不可重入

使用者态 / 核心态

可被中斷 / 不可被中斷

備注

CRITICAL_SECTION 臨界區

Windows

先自旋鎖,後睡眠鎖

可重入

使用者态

SRWLock 讀寫鎖

Windows

讀寫鎖

不可重入

使用者态

Mutex 互斥量

Windows

睡眠鎖

不可重入

核心态

spin_lock

Linux

自旋鎖

核心

Mutex 互斥量

Linux

睡眠鎖

pthread

rwlock

Linux

讀寫鎖

pthread

synchronized

JVM

類自旋鎖

可重入

JVM 内部鎖

ReentrantLock

JVM

類睡眠鎖

可重入

Java 類庫的鎖

ReentrantReadWriteLock

JVM

讀寫鎖

可重入

Java類庫的鎖

這裡着重說一下,何時使用自旋鎖,何時使用讀寫鎖,何時使用睡眠鎖。

在臨界區範圍較小,競争不強,并且其中沒有讀寫檔案之類的核心态操作時,最好使用自旋鎖;這是因為,自旋鎖是以一種“忙等”的方式搶占鎖,如果臨界區範圍較大,或競争很強,或者有核心态操作,導緻多個線程同時等待一個自旋鎖資源,伺服器的CPU使用率将會非常高,上下文切換會比較頻繁,性能不佳。對于Windows的臨界區,微軟特别做了優化,它會先自旋一段時間,然後,如果長時間進入不了臨界區,則會使用互斥量進入睡眠狀态。

在讀寫數量上差距很大時,(讀多寫少或者寫多讀少),使用讀寫鎖;讀寫鎖,大多數情況下都是自旋鎖的一個變種。

在臨界區範圍較大或者臨界區其中有核心态操作時,最好使用睡眠鎖;睡眠鎖在搶占不到鎖的情況下,會進入核心态,使自身所在的線程被挂起。在臨界區較小時,進入核心态的時間長度很可能大于在臨界區中的時間長度,導緻性能不佳,但是如果臨界區很大,其中操作時間長度大于睡眠鎖進入核心态的時間長度,尤其是在競争很強的情況下,性能相對自旋鎖要好些。

對于JVM,為什麼我會寫類自旋鎖和類睡眠鎖,這是因為,它們的性能情況和在C++下是不一樣的,在Java5.0中,synchronized的性能和ReentrantLock的性能的對比與自旋鎖和睡眠鎖的性能對比類似,但是在Java6.0中則不然,synchronized在競态的性能有了大幅的提高,使得在競态情況下,synchronized的性能和ReentrantLock的性能基本一緻。

最後,也是最重要的是,以上說法都不準确,唯一準确的是在你自己的代碼中測試性能的結果。