乾貨ReentrantLock非公平鎖源碼分析


天天早上七點三十,準時推送乾貨




hello~各位讀者好,我是鴨血粉絲(你們能夠稱呼我爲「阿粉」)。今天,阿粉帶着你們來了解一下 ReentrantLock 鎖的非公平鎖的實現原理java

1.鎖

java中,加鎖的方式web

1. synchronized,這個是 java 底層實現的,也就是 C 語言實現的。
2. lock,這個是 java.util.concurrent 包下面的,是 java語言實現的。

2.ReentrantLock

ReentrantLock 是 Lock 的一種實現,是一種可重入的公平或非公平鎖。默認是非公平鎖。微信

2.1 Lock的建立

首先看下鎖的建立和使用代碼:app

//建立鎖Lock lock = new ReentrantLock();//加鎖lock.lock();//釋放鎖lock.unlock();

而後看下建立的是 ReentrantLock 的構造函數:less

public ReentrantLock() { sync = new NonfairSync();}

NonfairSync 就是非公平鎖。因此 ReentrantLock 默認是非公平鎖的實現編輯器

2.2 lock()

加鎖的邏輯就比較複雜了,由於存在線程競爭。因此有兩種狀況,一種是競爭到鎖的處理,一種是沒有競爭到鎖的處理。函數

首先咱們仍是來看下 lock() 方法,由於最終是非公平的實現,因此直接看 NonfairSync 裏面的 lock 方法。oop

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個方法,阿粉一個一個的說。flex

  1. 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,說明以前得到鎖的線程已經釋放了,那麼這個線程就會再次去競爭鎖,這就是非公平鎖的體現,若是是公平鎖,是沒有這個判斷的。

    b. 若是前一個得到鎖的線程沒有釋放鎖,那麼就判斷是不是同一個線程,是的話就會將 state 加 1。這個就是重入鎖的體現。

    c. 若是都不知足,那麼返回 false。

  2. acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) ,再次獲取鎖沒有成功,而且又不是可重入鎖,那麼就存入一個阻塞隊列裏面。裏面還有一點邏輯,就不展開了,有興趣能夠本身看下。

  3. selfInterrupt(); 這個是當前線程的中斷標誌,做用就是在線程在阻塞的是否,客戶端經過調用了中斷線程的方法 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;}

釋放鎖的步驟

  1. state - 1,若是大於0,說明釋放的是重入鎖,只須要修改 state 就好了
  2. 若是等於0,說明要釋放鎖,釋放鎖首先須要把獨佔線程設置爲null,再把state設置爲0。

3 總結

Lock 鎖的實現:

  1. 互斥性:須要一個狀態來判斷是否競爭到鎖:state 而且須要用 volatile修飾,保證線程之間的可見性。

  2. 可重入性:Thread exclusiveOwnerThread 這個成員變量來記錄當前得到鎖的線程。

  3. 公平或非公平:默認非公平,NonfairSync。

  4. 沒有競爭到鎖的線程怎麼辦?放到隊列中。

  5. 沒有競爭到鎖的線程怎麼釋放CPU?park:阻塞線程釋放CPU資源,這個操做在 acquireQueued(),阿粉沒沒有講這個。

  6. 最後來張流程圖:

< END >

若是你們喜歡咱們的文章,歡迎你們轉發,點擊在看讓更多的人看到。也歡迎你們熱愛技術和學習的朋友加入的咱們的知識星球當中,咱們共同成長,進步。

往期 精彩回顧




秒殺真那麼難?手把手帶你優化秒殺流程
手把手教你搭建一個單一機器的Hadoop,你要看一下麼?
你肯定 LinkedList 在新增/刪除元素時,效率比 ArrayList 高?

本文分享自微信公衆號 - Java極客技術(Javageektech)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索