1. 程式人生 > >Java鎖及AbstractQueuedSynchronizer源碼分析

Java鎖及AbstractQueuedSynchronizer源碼分析

head pub ued 概念 urn 控制 等於 具體實現 backup

- lock

Lock實現提供了比使用synchronized方法和synchronized語句塊擴展性更好的鎖操作,他們允許更靈活地構建,可以有相當不同的屬性,並且可以支持多個相關的Condition對象
鎖是一個控制被多個線程共享的資源訪問的工具,一般來說,鎖對共享資源提供排它地訪問,
一個時間內只能一個線程可以獲取鎖並且要求獲取鎖的線程是所有對共享資源的訪問線種中的第一個。
然而,一些鎖可以允許對共享的資源並發訪問,比如ReadWriteLock的讀鎖

關於鎖的幾個概念

鎖重入
就是一個線程獲取鎖之後,這個線程還可以再次獲取相同鎖。
公平鎖
獲取鎖的過程采用類似排隊的機制,排在前面的線程先獲取鎖。
非公平鎖

獲取鎖的過程,不排隊,只要沒有線程持有鎖,就可以獲取鎖。


ReentrantLock是可重入鎖的一個實現。
AbstractQueuedSynchronizer是一個抽象類。它提供了很多關於鎖的基本操作。

ReentrantLock類裏有一個sync的字段。它繼承於AbstractQueuedSynchronizer。

先看獲取鎖的過程
public void lock() {
        sync.lock();
    }

它直接調用的sync對象的lock()方法。

Sync類提供了公平鎖和非公平鎖的公共操作。它的lock方法是一個抽象方法。具體實現在公平鎖
FairSync和非公平鎖實現NonfairSync中實現。首先先看公平鎖版本的實現


final void lock() {
       acquire(1);
}

acquire(1)這方法是在在AbstractQueuedSynchronizer中實現

public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

它大致做了如下幾個事情。

1 tryAcquire() 就是試圖獲取鎖,如果成功就結束

2 acquireQueued 如果試圖獲取失敗,就加入隊列中等待

3 addWaiter 新建表示當前線程的一個節點。加入隊列當中

4 selfInterrupt(),自己給自己一個中斷。

tryAcquire

這個方法在AbstractQueuedSynchronizer中是一個抽象的方法,具體實現就是子類中,這裏就是在

ReentrantLock的FairSync類裏面。
protected final boolean tryAcquire(int acquires) {
       1.獲取當前線程
final Thread current = Thread.currentThread();
       2.當前state值
int c = getState(); if (c == 0) { //如果c等於0,表示當前沒有線程占有鎖,可以直接獲取鎖 if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { //如果隊列中前面沒有其它等待的線程,就把狀態state值設置為1acquires值,這裏是1. setExclusiveOwnerThread(current); //把當前鎖的持有線程設置為當前線程 return true; } } else if (current == getExclusiveOwnerThread()) { //如果c不是0,說明已經有線程持有這個鎖,就看持有鎖的線程是不是當前線程,如果是就把state的值加1。然後更新它的值 int nextc = c + acquires; if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; }
hasQueuedPredecessors
public final boolean hasQueuedPredecessors() {
        Node t = tail; // 隊列的尾
        Node h = head; // 隊列的頭
        Node s;
        return h != t &&
            ((s = h.next) == null || s.thread != Thread.currentThread());
    }

這裏主要的判斷邏輯,就是如果頭和尾不相等,說明這個隊列就不為空,並且隊列的頭的下一下節點不是當前線程,就說明隊列中有前繼節點。

但是我第一次看這個代碼的時候,為什麽頭節點的next為null的時候,也說明有前繼節點呢,

compareAndSetState

這個一個CAS操作,就是原子地設置state的值,如果期望值是0,就設置state的值為傳入的值。
setExclusiveOwnerThread
這個方法是設置當前鎖的持有線程為當前線程,這個方法是在AbstractOwnableSynchronizer抽象類裏定義的,它是一個表示這一個鎖是由那個線程獨占持有的輔助類。
AbstractQueuedSynchronizer類繼承了這個類。


getExclusiveOwnerThread

如果試圖獲取鎖不成功,就進行下一步,首先就是把這個線程加入到隊列中,

private Node addWaiter(Node mode) {
        Node node = new Node(Thread.currentThread(), mode);
        // Try the fast path of enq; backup to full enq on failure
        Node pred = tail;
        if (pred != null) {
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        enq(node);
        return node;
    }
這個方法的入參是Node.EXCLUSIVE。表示這個節點正在以鎖是排它的


Java鎖及AbstractQueuedSynchronizer源碼分析