ReentrantLock深刻學習

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);
    }
}
相關文章
相關標籤/搜索