新聞中心
本文轉(zhuǎn)載自微信公眾號「Java極客技術」,作者鴨血粉絲。轉(zhuǎn)載本文請聯(lián)系Java極客技術公眾號。

專注于為中小企業(yè)提供網(wǎng)站建設、做網(wǎng)站服務,電腦端+手機端+微信端的三站合一,更高效的管理,為中小企業(yè)徽縣免費做網(wǎng)站提供優(yōu)質(zhì)的服務。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動了上千家企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網(wǎng)站建設實現(xiàn)規(guī)模擴充和轉(zhuǎn)變。
1.鎖
java中,加鎖的方式
- synchronized,這個是 java 底層實現(xiàn)的,也就是 C 語言實現(xiàn)的。
- . lock,這個是 java.util.concurrent 包下面的,是 java語言實現(xiàn)的。
2.ReentrantLock
ReentrantLock 是 Lock 的一種實現(xiàn),是一種可重入的公平或非公平鎖。默認是非公平鎖。
2.1 Lock的創(chuàng)建
首先看下鎖的創(chuàng)建和使用代碼:
- //創(chuàng)建鎖
- Lock lock = new ReentrantLock();
- //加鎖
- lock.lock();
- //釋放鎖
- lock.unlock();
然后看下創(chuàng)建的是 ReentrantLock 的構造函數(shù):
- public ReentrantLock() {
- sync = new NonfairSync();
- }
NonfairSync 就是非公平鎖。所以 ReentrantLock 默認是非公平鎖的實現(xiàn)
2.2 lock()
加鎖的邏輯就比較復雜了,因為存在線程競爭。所以有兩種情況,一種是競爭到鎖的處理,一種是沒有競爭到鎖的處理。
首先我們還是來看下 lock() 方法,因為最終是非公平的實現(xiàn),所以直接看 NonfairSync 里面的 lock 方法。
- final void lock() {
- if (compareAndSetState(0, 1))
- setExclusiveOwnerThread(Thread.currentThread());
- else
- acquire(1);
- }
2.3 沒有獲取到鎖的邏輯 acquire()
直接上代碼:
- public final void acquire(int arg) {
- if (!tryAcquire(arg) &&
- acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
- selfInterrupt();
- }
還是3個方法,阿粉一個一個的說。
tryAcquire(arg) ,還是先看代碼在分析。
- final boolean nonfairTryAcquire(int acquires) {
- final Thread current = Thread.currentThread();
- int c = getState();
- if (c == 0) {
- if (compareAndSetState(0, acquires)) {
- setExclusiveOwnerThread(current);
- return true;
- }
- }
- else if (current == getExclusiveOwnerThread()) {
- int nextc = c + acquires;
- if (nextc < 0) // overflow
- throw new Error("Maximum lock count exceeded");
- setState(nextc);
- return true;
- }
- return false;
- }
a. 獲取 state ,如果等于0,說明之前獲得鎖的線程已經(jīng)釋放了,那么這個線程就會再次去競爭鎖,這就是非公平鎖的體現(xiàn),如果是公平鎖,是沒有這個判斷的。
b. 如果前一個獲得鎖的線程沒有釋放鎖,那么就判斷是否是同一個線程,是的話就會將 state 加 1。這個就是重入鎖的體現(xiàn)。
c. 如果都不滿足,那么返回 false。
acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) ,再次獲取鎖沒有成功,并且又不是可重入鎖,那么就存入一個阻塞隊列里面。里面還有一點邏輯,就不展開了,有興趣可以自己看下。
selfInterrupt(); 這個是當前線程的中斷標志,作用就是在線程在阻塞的是否,客戶端通過調(diào)用了中斷線程的方法 interrupt(),那么該線程被喚醒的時候,就會有響應的處理。具體要看這個線程 run 方法里面的代碼邏輯。
2.4 unlock()
- protected final boolean tryRelease(int releases) {
- int c = getState() - releases;
- if (Thread.currentThread() != getExclusiveOwnerThread())
- throw new IllegalMonitorStateException();
- boolean free = false;
- if (c == 0) {
- free = true;
- setExclusiveOwnerThread(null);
- }
- setState(c);
- return free;
- }
state - 1,如果大于0,說明釋放的是重入鎖,只需要修改 state 就行了
如果等于0,說明要釋放鎖,釋放鎖首先需要把獨占線程設置為null,再把state設置為0。
3 總結(jié)
Lock 鎖的實現(xiàn):
互斥性:需要一個狀態(tài)來判斷是否競爭到鎖:state 并且需要用 volatile修飾,保證線程之間的可見性。
可重入性:Thread exclusiveOwnerThread 這個成員變量來記錄當前獲得鎖的線程。
公平或非公平:默認非公平,NonfairSync。
沒有競爭到鎖的線程怎么辦?放到隊列中。
沒有競爭到鎖的線程怎么釋放CPU?park:阻塞線程釋放CPU資源,這個操作在 acquireQueued(),阿粉沒沒有講這個。
最后來張流程圖:
網(wǎng)站欄目:干貨ReentrantLock非公平鎖源碼分析
文章分享:http://m.jiaoqi3.com/article/djochhs.html


咨詢
建站咨詢
