ReentrankLock 分爲 非公平鎖及公平鎖html
首先咱們看一下它裏面有哪些屬性:ide
private final Sync sync;
Sync 這個類是 ReentrantLock的 一個靜態內部類,實現了AbstractQueuedSynchronizer
ReentrantLock根據傳入構造方法的布爾型參數實例化出Sync的實現類FairSync和NonfairSync,分別表示公平的Sync和非公平的Sync
AbstractQueuedSynchronizer這個類中封裝了同步過程當中堵塞的線程隊列,它裏面對線程之間的切換,同步的佔用,作了很好的處理
像CountDownLatch、FutureTask、Semaphore、ReentrantLock等都有一個內部類是這個抽象類的子類
下面咱們介紹幾個ReentrantLock的核心方法及屬性:
private volatile int state;
這個屬性初始化爲0,表示當前沒有加鎖,每次lock()操做,便會累加這個值,一樣一個線程想要獲取這個鎖,作CAS操做的時候,也是判斷state的值是否爲0
NonfairSync鎖:
final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); }
fairSync鎖:
final void lock() {
acquire(1);
}
tryAcquire方法中,先 判斷當前state值是不是0,若爲0 ,則可進行嘗試加鎖。若不爲0,判斷做這個加鎖操做的是否爲當前線程,若爲當前線程,則直接累加,而後更新state值ui
setExclusiveOwnerThread(current) 是設置當前線程爲佔有線程spa
fairSync鎖:
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
NonfairSync鎖:
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; }
一樣,unlock(),則會在這個值 上進行-1。從代碼上看最終會調用tryRelease 方法,咱們能夠看到以後在state值爲0的時候,纔會清空當前佔有線程。
當state爲0時,tryRelease 返回的則是true, 則會判斷head是否爲null(不爲空則表示有阻塞線程,這裏阻塞隊列這裏怎麼處理,能夠看AbstractQueuedSynchronizer的處理,參考:http://www.cnblogs.com/xrq730/p/4979021.html)
以後,會進行unparkSuccessor()的處理,這個方法是AbstractQueuedSynchronizer的方法最終會調用LockSupport.unpark(s.thread);s.thread 爲阻塞隊列中的一個線程,應該是最接近head的阻塞線程(head爲阻塞隊列的頭指針)
public void unlock() { sync.release(1); }
public final boolean release(int arg) { if (tryRelease(arg)) { Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h); return true; } return false; }
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; }
在看JDK源代碼的時候,咱們會常常的看到try開頭的方法,這些方法都是無鎖的方式,經過CAS進行屢次嘗試,會自旋式的獲取鎖,只有在必定時間內,仍沒有獲取到鎖,纔會進行park操做(unsafe的park操做,將線程掛起)線程
final Thread getOwner()
獲取當前佔有線程
final int getHoldCount()
獲取當前的state值
public final int getQueueLength()
獲取阻塞隊列的長度
最後,附上簡單的使用代碼:
public class ReentrantLockDemo { private static int i=0; public static void main(String[] args) throws InterruptedException { final ReentrantLock myLock = new ReentrantLock(); Thread thread1=new Thread(new Runnable() { @Override public void run() { for(int j=0;j<1000;j++){ myLock.lock(); i++; try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } myLock.unlock(); } } }); Thread thread2=new Thread(new Runnable() { @Override public void run() { for(int j=0;j<1000;j++){ myLock.lock(); i++; try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } myLock.unlock(); } } }); thread1.start(); thread2.start(); thread1.join(); thread2.join(); System.out.println(i); } }