【ReentrantLock】AND【ReentrantReadWriteLock】

ReentrantLock

實現Lock接口的一個類支持重入性,表示能夠對共享資源能夠重複加鎖,及當前線程再次獲取該鎖不會被阻塞
1.鎖的可重入

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;
}

執行兩種邏輯1.當前鎖未被任何線程佔有 則鎖被當前線程獲取 2.已經被線程佔有判斷是否是當前線程 ,如果是則獲取鎖對象計數+1
釋放鎖

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;
}
``
同步鎖釋放必須等到同步狀態爲0才能成功釋放,當一個鎖獲取一次,計數+1,所以釋放一次計數-1,若返回值同步狀態不爲0則爲false
2.公平鎖與非公平鎖
一個公平鎖獲取順序符合FIFO先到先得
ReentranLock無參構造時非公平鎖
傳入參數true公平鎖false非公平鎖
```javascript
public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

公平鎖每次都是從同步隊列第一個節點獲取鎖,而非公平鎖則不一定,所以公平鎖保證請求資源的絕對順序但是性能開銷高於非公平鎖。
ReentrantReadWriteLock

1.讀寫鎖
獨佔鎖一般synchhronized或者concurrents實現Lock接口ReentrantLock實現獨佔鎖,同一時刻只有一個線程能夠獲取鎖
讀寫所允許同一時刻被多個讀線程訪問,但是在寫線程訪問時,所有的讀線程和其他的寫線程都會被阻塞。
2.寫鎖的獲取
同一時刻寫鎖不能被多個線程鎖獲取,寫鎖時獨佔式鎖實現的方式重寫AQS中的tryAcquire方法實現

protected final boolean tryAcquire(int acquires) {
    Thread current = Thread.currentThread(); 
    int c = getState();    // 1. 獲取寫鎖當前的同步狀態
    int w = exclusiveCount(c);  // 2. 獲取寫鎖獲取的次數
    if (c != 0) {
        // (Note: if c != 0 and w == 0 then shared count != 0)
		// 3.1 當讀鎖已被讀線程獲取或者當前線程不是已經獲取寫鎖的線程的話
		// 當前線程獲取寫鎖失敗
        if (w == 0 || current != getExclusiveOwnerThread())
            return false;
        if (w + exclusiveCount(acquires) > MAX_COUNT)
            throw new Error("Maximum lock count exceeded");
        // Reentrant acquire
		// 3.2 當前線程獲取寫鎖,支持可重複加鎖
        setState(c + acquires);   //acquires重複加鎖
        return true;
    }
	// 3.3 寫鎖未被任何線程獲取,當前線程可獲取寫鎖
    if (writerShouldBlock() ||
        !compareAndSetState(c, c + acquires))
        return false;
    setExclusiveOwnerThread(current);
    return true;
}

3.寫鎖的釋放
重寫AQS的tryRelease方法完成寫鎖的釋放

protected final boolean tryRelease(int releases) {
    if (!isHeldExclusively())
        throw new IllegalMonitorStateException();
	//1. 同步狀態減去寫狀態
    int nextc = getState() - releases;
	//2. 當前寫狀態是否爲0,爲0則釋放寫鎖
    boolean free = exclusiveCount(nextc) == 0;
    if (free)
        setExclusiveOwnerThread(null);
	//3. 不爲0則更新同步狀態
    setState(nextc);
    return free;
}

同步狀態的情況下進入寫鎖類似於可重入鎖的方式,將寫鎖也是爲重入鎖所以在釋放時,用同步狀態減去寫狀態帶來的Monitor++;
4.讀鎖
讀鎖不是獨佔式鎖,同一時刻多個線程可以同時獲取的一種共享鎖的方式

    Thread current = Thread.currentThread();
    int c = getState();
	//1. 如果寫鎖已經被獲取並且獲取寫鎖的線程不是當前線程的話,當前
	// 線程獲取讀鎖失敗返回-1
    if (exclusiveCount(c) != 0 &&
        getExclusiveOwnerThread() != current)
        return -1;
    int r = sharedCount(c);
    if (!readerShouldBlock() &&
        r < MAX_COUNT &&
		//2. 當前線程獲取讀鎖
        compareAndSetState(c, c + SHARED_UNIT)) {
		//3. 下面的代碼主要是新增的一些功能,比如getReadHoldCount()方法
		//返回當前獲取讀鎖的次數
        if (r == 0) {
            firstReader = current;
            firstReaderHoldCount = 1;
        } else if (firstReader == current) {
            firstReaderHoldCount++;
        } else {
            HoldCounter rh = cachedHoldCounter;
            if (rh == null || rh.tid != getThreadId(current))
                cachedHoldCounter = rh = readHolds.get();
            else if (rh.count == 0)
                readHolds.set(rh);
            rh.count++;
        }
        return 1;
    }
	//4. 處理在第二步中CAS操作失敗的自旋已經實現重入性
    return fullTryAcquireShared(current);
}

(1). 與寫鎖邏輯相同,對當前鎖的狀態進行胖多,如果寫鎖被獲取,但是寫鎖線程不是當前線程,則失敗不能進入寫鎖,CAS自旋成功進入,更新狀態
(2). 當前線程成功獲取讀鎖,返回讀鎖的次數
5.讀鎖的釋放

protected final boolean tryReleaseShared(int unused) {
    Thread current = Thread.currentThread();
    if (firstReader == current) {
        // assert firstReaderHoldCount > 0;
        if (firstReaderHoldCount == 1)
            firstReader = null;
        else
            firstReaderHoldCount--;
    } else {
        HoldCounter rh = cachedHoldCounter;
        if (rh == null || rh.tid != getThreadId(current))
            rh = readHolds.get();
        int count = rh.count;
        if (count <= 1) {
            readHolds.remove();
            if (count <= 0)
                throw unmatchedUnlockException();
        }
        --rh.count;
    }
    for (;;) {
        int c = getState();
		// 讀鎖釋放 將同步狀態減去讀狀態即可
        int nextc = c - SHARED_UNIT;
        if (compareAndSetState(c, nextc))
            // Releasing the read lock has no effect on readers,
            // but it may allow waiting writers to proceed if
            // both read and write locks are now free.
            return nextc == 0;
    }
}

6.鎖降級
讀寫鎖支持鎖降級,遵循按照獲取寫鎖,獲取讀鎖再釋放寫鎖的次序,寫鎖能夠降級成爲讀鎖。

[資源參考:https://www.jianshu.com/p/27860941a77b?tdsourcetag=s_pcqq_aiomsg 特此聲明]

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章