Java鎖系列教程之獨佔式鎖
在Java併發編程中,鎖是一個很重要的對象。Java中鎖有兩種:隱式鎖和顯式鎖。使用synchronized關鍵字的鎖是隱式鎖。因為鎖的申請和釋放都是由JVM來維護的,不用我們來手動處理。使用Java併發包locks包下的鎖,需要使用者手動申請和手動關閉。這種形式是顯式鎖。如果按照多個線程能不能共享同一個鎖(資源)來分的話,可以分為獨佔式(排他)鎖和共享鎖。其中synchronized關鍵字的鎖和ReentrantLock鎖的鎖都是獨佔式鎖。
通過前面三篇文章的學習,我們知道了同步組件基礎框架-AbstractQueuedSynchronizer(AQS) 同步器。在同步器的方法中有兩種方式獲取鎖:獨佔式和共享式鎖。我們先來學習獨佔式鎖-ReentrantLock。
本篇是《凱哥(凱哥Java:kagejava)併發編程學習》系列之《Lock系列》教程的第四篇:《Java併發包下鎖學習第四篇:ReentrantLock》。
ReentrantLock使用語法
我們知道併發包下的lock是顯式鎖,需要手動獲取鎖和手動釋放鎖。所以語法如下:
ReentrantLock lock = new ReentrantLock();
try {
lock.lock();
//TODO
}finally {
lock.unlock();
}
獲取鎖:lock.lock();
釋放鎖:lock.unlock();
在try中獲取到鎖;在finally中釋放鎖。
因為必須釋放鎖。所以,必須在finally中進行釋放鎖操作。而且釋放鎖操作必須放在finally的第一行。
獨佔式鎖理解:
生活中的例子:
在自動ATM機上取錢的時候,我們需要排隊,當一個人在操作ATM機取錢的時候,下一個人就需要在ATM機黃線外面等待(排除和取錢人一起去的人)。假設路人甲在操作ATM機的時候,我們其他後面排隊的人是不是需要等待著,路人甲從ATM機區域出來後才可以進行操作ATM機。這個操作過程如果放在我們多線程併發角度來思考的話:共享數據是ATM機,多個線程是多個存取錢的人。當路人甲在操作ATM機的時候路人甲獲取到ATM機操作權限可以理解為lock.lock()操作。這個時候,共享數據ATM機就會被路人甲獨自一個人佔用了(獨佔式獲取到了共享數據(或者是鎖))。當路人甲操作完離開ATM機這個操作可以理解為lock.unlock()操作。
從上了生活例子中我們可以這麼理解獨佔式鎖,所謂的獨佔式鎖就是同一時刻只能有且只有一個線程獲取到鎖且操作成功,其他線程只能等待釋放鎖後,在進行操作。
需要說明的是,在Java中隱式鎖(synchronized關鍵字修飾的)也是獨佔式鎖的一種體現。
使用方法一:獨佔非公平演示
需求:使用三個線程,調用一個方法,在方法內睡眠2s.代碼下圖:
查看運行結果:
線程2開始獲取鎖。
線程3開始獲取鎖。
線程1開始獲取鎖。
線程2獲取到了鎖。開始做其他的操作了====do..........
======關閉鎖=======
線程3獲取到了鎖。開始做其他的操作了====do..........
======關閉鎖=======
線程1獲取到了鎖。開始做其他的操作了====do..........
======關閉鎖=======
從上圖運行結果,我們可以分析出:
1:線程的順序和我們線程運行的順序不一致
2:每次只能有一個線程執行完關閉鎖之後,其他線程才可以接著使用。
從示例代碼,我們可以得到如下總結:
1:reentrantLock是獨佔式鎖;
2:默認情況下不能保證獲取鎖的順序和線程執行順序的一致性。
如果想要保證線程執行順序和獲取鎖的順序一致性,也是可以操作的。在下一篇文章中,凱哥將講解怎麼操作。
閱讀更多 凱哥java 的文章