一、前言
Java中的鎖有各種特性,比如可重入與不可重入,公平與非公平等,也可以根據(jù)這些特性進行分類。
二、可重入鎖
- 當某個線程請求一個由其他線程持有的鎖的時,發(fā)出請求的的線程就會阻塞。但當一個線程再次請求自己持有的對象鎖時,如果能請求成功,說明這個鎖是可重入的。也就是說線程可以重復(fù)的獲得已經(jīng)持有的鎖;
- 拿synchronized來說,synchronized的鎖是原子性的,也是可重入的,因此一個線程調(diào)用synchronized方法的同時在其方法體內(nèi)部調(diào)用該對象的另一個synchronized方法將不會進入阻塞狀態(tài),也就是說一個線程得到對象鎖后再次請求該對象鎖是允許的,這就是synchronized的可重入性。
看一段代碼:
public class ThreadTest extends SuperClass {
public synchronized void test(Thread thread) {
System.out.println(thread.getName());
super.test();
}
}
class SuperClass {
public synchronized void test() {
System.out.println(Thread.currentThread().getName());
}
}
??子類重寫了父類的test方法,然后調(diào)用父類的方法,此時如果沒有可重入的鎖,那么這段代碼將會產(chǎn)生死鎖。因為兩個方法都是synchronized方法,因此每個test方法再執(zhí)行前都會獲取SuperClass對象鎖,然后如果該鎖不是可重入的,那么在調(diào)用super.test方法時將無法獲得SuperClass對象上的鎖,因為這個鎖已經(jīng)被持有,從而線程將永遠停頓下去,等待一個永遠也無法獲得的鎖。
- 可重入鎖的一種實現(xiàn)方式是為每個鎖關(guān)聯(lián)一個計數(shù)值和一個所有者線程。當計數(shù)器為0時,這個鎖就被認為是沒有被任何線程持有,當線程請求一個未被持有的鎖時,JVM將記下鎖的持有者,并且將獲取計數(shù)值置為1,如果同一個線程再次獲取這個鎖,計數(shù)值遞增,而當線程退出同步代碼塊時,計數(shù)器會相應(yīng)的遞減,當計數(shù)器為0時,該鎖被釋放。
- 可重入鎖,有時也被稱為遞歸鎖,也就是說外層代碼獲取該鎖之后,內(nèi)層遞歸函數(shù)仍然可以獲得該鎖,JAVA中,
ReentrantLock和synchronized都是 可重入鎖;- 可重入鎖的最大作用就是可以避免死鎖;
二、可中斷鎖
- 可中斷鎖,顧名思義就是可以中斷阻塞中的鎖,Java中的synchronized由于不可中斷,不是可中斷鎖,而Lock則是可中斷鎖。
- 通俗的來說,如果某一線程A正在執(zhí)行鎖中的代碼,另一線程B正在等待獲取該鎖,可能由于等待時間過長,線程B不想等待了,想先處理其他事情,我們可以讓它中斷自己或者在別的線程中中斷它,這種就是可中斷鎖。
三、讀寫鎖
??就是說對資源的訪問操作分為讀鎖和寫鎖,分開來進行。就是因為有了讀寫鎖,才使得多個線程之間的讀操作不會發(fā)生沖突,對應(yīng)的接口是ReadWriteLock,該接口對應(yīng)的實現(xiàn)類是ReentrantReadWriteLock,可以通過對應(yīng)的readLock()方法獲取讀鎖,通過writeLock()方法獲取寫鎖,后續(xù)我們會學(xué)習(xí)到。
四、公平鎖
??公平鎖是說根據(jù)請求鎖的順序來獲取鎖,比如同時有多個線程在等待獲取鎖的時候,最先請求的線程會獲取該鎖(也就是等待時間最長的線程),這種就是公平鎖。非公平鎖就無法保證這點了,但需要注意下:
- Java中的synchronized是一種非公平鎖,無法保證最先請求的線程先獲取到鎖,而ReentrantLock和ReentrantReadWriteLock,默認情況下是非公平鎖,但可以設(shè)置為公平鎖,后續(xù)我們學(xué)習(xí)到這里的時候再說。
- 對ReentrantLock來說,即使是公平鎖,對于可輪詢的tryLock仍然有可能會出現(xiàn)“插隊”的現(xiàn)象,也就是不按線程請求順序的情況。所以說即使是公平鎖,也不一定能確保線程調(diào)度器是公平的。如果線程調(diào)度器選擇忽略一個線程,而該線程恰好是等待時間最長的那個,那么就沒有機會公平的處理這個鎖了。
- 公平鎖的實現(xiàn)需要通過一個隊列來維護線程請求的順序性,并且在進行等待和喚醒線程時存在一定的性能開銷,而非公平性則不用考慮這些,所以大多數(shù)情況下,非公平鎖的性能要高于公平鎖的性能。但當持有鎖的實際相對較長,或者請求鎖的平均時間間隔較長的時候,這時候可以使用公平鎖。
本文參考自:
海子-Java并發(fā)編程-Lock
《Java并發(fā)編程實戰(zhàn)》
《Java核心技術(shù)》