欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中ReentrantLock和ReentrantReadWriteLock的原理

 更新時(shí)間:2022年09月08日 10:07:35   作者:會(huì)飛的湯姆貓???????  
這篇文章主要介紹了Java中ReentrantLock和ReentrantReadWriteLock的原理,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,感興趣的小伙伴可以參考一下

ReentrantLock 原理

概念

基于AQS實(shí)現(xiàn)的可重入鎖實(shí)現(xiàn)類。

核心變量和構(gòu)造器

public class ReentrantLock implements Lock, java.io.Serializable {
 ? ?private final Sync sync;
 ? ?public ReentrantLock() {
 ? ? ? ?// 默認(rèn)為非公平鎖。為何默認(rèn)為非公平鎖?因?yàn)橥ㄟ^大量測(cè)試下來,發(fā)現(xiàn)非公平鎖的性能優(yōu)于公平鎖
 ? ? ? ?sync = new NonfairSync();
 ?  }
 ? ?public ReentrantLock(boolean fair) {
 ? ? ? ?// 由fair變量來表明選擇鎖類型
 ? ? ? ?sync = fair ? new FairSync() : new NonfairSync();
 ?  }
 ? ?abstract static class Sync extends AbstractQueuedSynchronizer {
 ? ? ? ?abstract void lock();
 ? ? ? ?// 非公平鎖標(biāo)準(zhǔn)獲取鎖方法
 ? ? ? ?final boolean nonfairTryAcquire(int acquires) {
 ? ? ? ? ? ?final Thread current = Thread.currentThread();
 ? ? ? ? ? ?int c = getState();
 ? ? ? ? ? ?// 當(dāng)執(zhí)行到這里時(shí),正好獲取所得線程釋放了鎖,那么可以嘗試搶鎖
 ? ? ? ? ? ?if (c == 0) {
 ? ? ? ? ? ? ? ?// 繼續(xù)搶鎖,不看有沒有線程排隊(duì)
 ? ? ? ? ? ? ? ?if (compareAndSetState(0, acquires)) {
 ? ? ? ? ? ? ? ? ? ?setExclusiveOwnerThread(current);
 ? ? ? ? ? ? ? ? ? ?return true;
 ? ? ? ? ? ? ?  }
 ? ? ? ? ?  }
 ? ? ? ? ? ?// 當(dāng)前線程就是持有鎖的線程,表明鎖重入
 ? ? ? ? ? ?else if (current == getExclusiveOwnerThread()) {
 ? ? ? ? ? ? ? ?// 利用state整形變量進(jìn)行次數(shù)記錄
 ? ? ? ? ? ? ? ?int nextc = c + acquires;
 ? ? ? ? ? ? ? ?// 如果超過了int表示范圍,表明符號(hào)溢出,所以拋出異常0111 1111 + 1 = 1000 0000 
 ? ? ? ? ? ? ? ?if (nextc < 0)
 ? ? ? ? ? ? ? ? ? ?throw new Error("Maximum lock count exceeded");
 ? ? ? ? ? ? ? ?setState(nextc);
 ? ? ? ? ? ? ? ?return true;
 ? ? ? ? ?  }
 ? ? ? ? ? ?// 返回false 表明需要AQS來將當(dāng)前線程放入阻塞隊(duì)列,然后進(jìn)行阻塞操作等待喚醒獲取鎖
 ? ? ? ? ? ?return false;
 ? ? ?  }
 ? ? ? ?// 公平鎖和非公平鎖公用方法,因?yàn)樵卺尫沛i的時(shí)候,并不區(qū)分是否公平
 ? ? ? ?protected final boolean tryRelease(int releases) {
 ? ? ? ? ? ?int c = getState() - releases;
 ? ? ? ? ? ?// 如果當(dāng)前線程不是上鎖的那個(gè)線程
 ? ? ? ? ? ?if (Thread.currentThread() != getExclusiveOwnerThread())
 ? ? ? ? ? ? ? ?throw new IllegalMonitorStateException();
 ? ? ? ? ? ?boolean free = false;
 ? ? ? ? ? ?// 不是重入鎖,那么當(dāng)前線程一定是釋放鎖了,然后我們把當(dāng)前AQS用于保存當(dāng)前鎖對(duì)象的變量ExclusiveOwnerThread設(shè)置為null,表明釋放鎖成功
 ? ? ? ? ? ?if (c == 0) {
 ? ? ? ? ? ? ? ?free = true;
 ? ? ? ? ? ? ? ?setExclusiveOwnerThread(null);
 ? ? ? ? ?  }
 ? ? ? ? ? ?// 注意:此時(shí)state全局變量沒有改變,也就意味著在setState之前,沒有別的線程能夠獲取鎖,這時(shí)保證了以上的操作原子性
 ? ? ? ? ? ?setState(c);
 ? ? ? ? ? ?// 告訴AQS,我當(dāng)前釋放鎖成功了,你可以去喚醒正在等待鎖的線程了
 ? ? ? ? ? ?return free;
 ? ? ?  }
?
 ? ? ? ?protected final boolean isHeldExclusively() {
 ? ? ? ? ? ?return getExclusiveOwnerThread() == Thread.currentThread();
 ? ? ?  }
?
 ? ? ? ?final ConditionObject newCondition() {
 ? ? ? ? ? ?return new ConditionObject();
 ? ? ?  }
?
 ?  }
?
 ? ?static final class NonfairSync extends Sync {
 ? ? ? ?// 由ReentrantLock調(diào)用獲取鎖
 ? ? ? ?final void lock() {
 ? ? ? ? ? ?// 非公平鎖,直接搶鎖,不管有沒有線程排隊(duì)
 ? ? ? ? ? ?if (compareAndSetState(0, 1))
 ? ? ? ? ? ? ? ?// 上鎖成功,那么標(biāo)識(shí)當(dāng)前線程為獲取鎖的線程
 ? ? ? ? ? ? ? ?setExclusiveOwnerThread(Thread.currentThread());
 ? ? ? ? ? ?else
 ? ? ? ? ? ? ? ?// 搶鎖失敗,進(jìn)入AQS的標(biāo)準(zhǔn)獲取鎖流程
 ? ? ? ? ? ? ? ?acquire(1);
 ? ? ?  }
?
 ? ? ? ?protected final boolean tryAcquire(int acquires) {
 ? ? ? ? ? ?// 使用父類提供的獲取非公平鎖的方法來獲取鎖
 ? ? ? ? ? ?return nonfairTryAcquire(acquires);
 ? ? ?  }
 ?  }?
 ? ?static final class FairSync extends Sync {
 ? ? ? ?// 由ReentrantLock調(diào)用
 ? ? ? ?final void lock() {
 ? ? ? ? ? ?// 沒有嘗試搶鎖,直接進(jìn)入AQS標(biāo)準(zhǔn)獲取鎖流程
 ? ? ? ? ? ?acquire(1);
 ? ? ?  }
 ? ? ? ?// AQS調(diào)用,子類自己實(shí)現(xiàn)獲取鎖的流程
 ? ? ? ?protected final boolean tryAcquire(int acquires) {
 ? ? ? ? ? ?final Thread current = Thread.currentThread();
 ? ? ? ? ? ?int c = getState();
 ? ? ? ? ? ?// 此時(shí)有可能正好獲取鎖的線程釋放了鎖,也有可能本身就沒有線程獲取鎖
 ? ? ? ? ? ?if (c == 0) {
 ? ? ? ? ? ? ? ?// 注意:這里和非公平鎖的區(qū)別在于:hasQueuedPredecessors看看隊(duì)列中是否有線程正在排隊(duì),沒有的話再通過CAS搶鎖
 ? ? ? ? ? ? ? ?if (!hasQueuedPredecessors() &&
 ? ? ? ? ? ? ? ? ? ?compareAndSetState(0, acquires)) {
 ? ? ? ? ? ? ? ? ? ?// 搶鎖成功
 ? ? ? ? ? ? ? ? ? ?setExclusiveOwnerThread(current);
 ? ? ? ? ? ? ? ? ? ?return true;
 ? ? ? ? ? ? ?  }
 ? ? ? ? ?  }
 ? ? ? ? ? ?// 當(dāng)前線程就是獲取鎖的線程,那么這里是鎖重入,和非公平鎖操作一模一樣
 ? ? ? ? ? ?else if (current == getExclusiveOwnerThread()) {
 ? ? ? ? ? ? ? ?int nextc = c + acquires;
 ? ? ? ? ? ? ? ?if (nextc < 0)
 ? ? ? ? ? ? ? ? ? ?throw new Error("Maximum lock count exceeded");
 ? ? ? ? ? ? ? ?setState(nextc);
 ? ? ? ? ? ? ? ?return true;
 ? ? ? ? ?  }
 ? ? ? ? ? ?// 返回false 表明需要AQS來將當(dāng)前線程放入阻塞隊(duì)列,然后進(jìn)行阻塞操作等待喚醒獲取鎖
 ? ? ? ? ? ?return false;
 ? ? ?  }
 ?  }
}

核心方法

獲取鎖操作:

public void lock() {
 ? ?// 直接通過sync同步器上鎖
 ? ?sync.lock();
}

釋放鎖操作:

public void unlock() {
 ? ?sync.release(1);
}

ReentrantReadWriteLock 原理

用例

將原來的鎖,分割為兩把鎖:讀鎖、寫鎖。適用于讀多寫少的場(chǎng)景,讀鎖可以并發(fā),寫鎖與其他鎖互斥。寫寫互斥、寫讀互斥、讀讀兼容。

public class ThreadDemo {
 ? ?static volatile int a;?
 ? ?public static void readA() {
 ? ? ? ?System.out.println(a);
 ?  }?
 ? ?public static void writeA() {
 ? ? ? ?a++;
 ?  }
 ? ?public static void main(String[] args) {
 ? ? ? ?ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
 ? ? ? ?ReentrantReadWriteLock.ReadLock readLock = reentrantReadWriteLock.readLock();
 ? ? ? ?ReentrantReadWriteLock.WriteLock writeLock = reentrantReadWriteLock.writeLock();
 ? ? ? ?Thread readThread1 = new Thread(() -> {
 ? ? ? ? ? ?readLock.lock();
 ? ? ? ? ? ?try {
 ? ? ? ? ? ? ? ?readA();
 ? ? ? ? ?  } finally {
 ? ? ? ? ? ? ? ?readLock.unlock();
 ? ? ? ? ?  }
?
 ? ? ?  });
 ? ? ? ?Thread readThread2 = new Thread(() -> {
 ? ? ? ? ? ?readLock.lock();
 ? ? ? ? ? ?try {
 ? ? ? ? ? ? ? ?readA();
 ? ? ? ? ?  } finally {
 ? ? ? ? ? ? ? ?readLock.unlock();
 ? ? ? ? ?  }
 ? ? ?  });
?
 ? ? ? ?Thread writeThread = new Thread(() -> {
 ? ? ? ? ? ?writeLock.lock();
 ? ? ? ? ? ?try {
 ? ? ? ? ? ? ? ?writeA();
 ? ? ? ? ?  } finally {
 ? ? ? ? ? ? ? ?writeLock.unlock();
 ? ? ? ? ?  }
 ? ? ?  });
?
 ? ? ? ?readThread1.start();
 ? ? ? ?readThread2.start();
 ? ? ? ?writeThread.start();
 ?  }
}

核心變量和構(gòu)造器

該接口用于獲取讀鎖和寫鎖對(duì)象

public interface ReadWriteLock {
 ? ?// 用于獲取讀鎖
 ? ?Lock readLock();
 ? ?// 用于獲取寫鎖
 ? ?Lock writeLock();
}

readerLock和writerLock變量用于支撐以上描述的ReadWriteLock接口的讀鎖和寫鎖方法。通過構(gòu)造方法得知,讀寫鎖對(duì)象的創(chuàng)建和用例均依賴于公平鎖或者非公平鎖同步器。

public class ReentrantReadWriteLock implements ReadWriteLock {
 ? ?// 讀鎖對(duì)象
 ? ?private final ReentrantReadWriteLock.ReadLock readerLock;
 ? ?// 寫鎖對(duì)象
 ? ?private final ReentrantReadWriteLock.WriteLock writerLock;
 ? ?// 同步器
 ? ?final Sync sync;
 ? ?// 默認(rèn)構(gòu)造器,創(chuàng)建了非公平鎖
 ? ?public ReentrantReadWriteLock() {
 ? ? ? ?this(false);
 ?  }
 ? ?// 根據(jù)fair變量,來選擇創(chuàng)建不同的鎖:公平鎖 FairSync 和非公平鎖 NonfairSync
 ? ?public ReentrantReadWriteLock(boolean fair) {
 ? ? ? ?sync = fair ? new FairSync() : new NonfairSync();
 ? ? ? ?// 用同步器來創(chuàng)建讀寫鎖對(duì)象
 ? ? ? ?readerLock = new ReadLock(this);
 ? ? ? ?writerLock = new WriteLock(this);
 ?  }
 ? ?public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock; }
 ? ?public ReentrantReadWriteLock.ReadLock ?readLock()  { return readerLock; } ? ?
}

Sync類

核心變量和構(gòu)造器

我們說讀鎖可以多個(gè)線程同時(shí)持有,而寫鎖只允許一個(gè)線程持有,此時(shí)我們稱 讀鎖-----共享鎖 寫鎖------互斥鎖(排他鎖)。然后我們?cè)贏QS中了解到一個(gè)變量state,它是32位的值,那么我們這里將其切割為高16位和低16位。

abstract static class Sync extends AbstractQueuedSynchronizer {
 ? ?// 高16位用于表示讀鎖
 ? ?static final int SHARED_SHIFT ? = 16;
 ? ?// 用于對(duì)高16位操作:加1 減1 
 ? ?static final int SHARED_UNIT ? ?= (1 << SHARED_SHIFT);
 ? ?// 最大讀鎖量
 ? ?static final int MAX_COUNT ? ? ?= (1 << SHARED_SHIFT) - 1;
 ? ?// 用于獲取低16位的值。例如 獲取低八位:0000 0000 1111 1111
 ? ?static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
?
 ? ?/** 獲取當(dāng)前持有讀鎖的線程數(shù)量  */
 ? ?static int sharedCount(int c) ?  { return c >>> SHARED_SHIFT; }
 ? ?/** 獲取當(dāng)前持有寫鎖的線程數(shù)量 */
 ? ?static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
?
 ? ?// 高16位為所有讀鎖獲取,那么我想知道每個(gè)線程對(duì)于讀鎖重入的次數(shù)?采用ThreadLocal來進(jìn)行統(tǒng)計(jì),每個(gè)線程自己統(tǒng)計(jì)自己的
 ? ?static final class HoldCounter {
 ? ? ? ?int count = 0;
 ? ? ? ?final long tid = getThreadId(Thread.currentThread());
 ?  }
 ? ?// 繼承自ThreadLocal,重寫了其中的initialValue方法,該方法將在線程第一次獲取該變量時(shí)調(diào)用初始化HoldCounter計(jì)數(shù)器
 ? ?static final class ThreadLocalHoldCounter
 ? ? ? ?extends ThreadLocal<HoldCounter> {
 ? ? ? ?public HoldCounter initialValue() {
 ? ? ? ? ? ?return new HoldCounter();
 ? ? ?  }
 ?  }
 ? ?// 創(chuàng)建ThreadLocal對(duì)象
 ? ?private transient ThreadLocalHoldCounter readHolds;
 ? ?// 緩存最后一個(gè)線程獲取的讀鎖數(shù)量
 ? ?private transient HoldCounter cachedHoldCounter;
 ? ?// 保存獲取到該鎖的第一個(gè)讀鎖線程
 ? ?private transient Thread firstReader = null;
 ? ?// 保存第一個(gè)該鎖的第一個(gè)讀鎖線程獲取到的讀鎖數(shù)量
 ? ?private transient int firstReaderHoldCount;
?
 ? ?Sync() {
 ? ? ? ?// 構(gòu)造器中初始化ThreadLocalHoldCounter ThreadLocal對(duì)象
 ? ? ? ?readHolds = new ThreadLocalHoldCounter();
 ? ? ? ?// 用于保證可見性,使用了state變量的volatile語(yǔ)義
 ? ? ? ?setState(getState()); 
 ?  }
}

tryAcquire獲取寫鎖的流程

由AQS調(diào)用,用于子類實(shí)現(xiàn)自己的上鎖邏輯,和原有獲取互斥鎖保持一致,

protected final boolean tryAcquire(int acquires) {
 ? ?// 獲取當(dāng)前線程
 ? ?Thread current = Thread.currentThread();
 ? ?// 獲取當(dāng)前狀態(tài)值和互斥鎖的數(shù)量
 ? ?int c = getState();
 ? ?int w = exclusiveCount(c);
 ? ?// 狀態(tài)值有效
 ? ?if (c != 0) {
 ? ? ? ?// 有線程獲取到了讀鎖或者當(dāng)前線程不是持有互斥鎖的線程
 ? ? ? ?if (w == 0 || ?// 有線程獲取到了讀鎖
 ? ? ? ? ? ?current != getExclusiveOwnerThread()) // 有線程獲取到了寫鎖
 ? ? ? ? ? ?// 返回false 讓AQS執(zhí)行阻塞操作
 ? ? ? ? ? ?return false;
 ? ? ? ?// 寫鎖重入,而又由于寫鎖的數(shù)量保存在低16位,所以直接加就行了
 ? ? ? ?if (w + exclusiveCount(acquires) > MAX_COUNT)
 ? ? ? ? ? ?throw new Error("Maximum lock count exceeded");
 ? ? ? ?setState(c + acquires);
 ? ? ? ?return true;
 ?  }
 ? ?// 既沒有讀鎖,也沒有寫鎖
 ? ?if (writerShouldBlock() || // 由子類實(shí)現(xiàn)判斷當(dāng)前線程是否應(yīng)該獲取寫鎖
 ? ? ? ?!compareAndSetState(c, c + acquires)) // 通過CAS搶寫鎖
 ? ? ? ?return false;
 ? ?// 獲取寫鎖成功,那么將當(dāng)前線程標(biāo)識(shí)為獲取互斥鎖的線程對(duì)象
 ? ?setExclusiveOwnerThread(current);
 ? ?return true;
}

tryAcquireShared獲取讀鎖的流程獲取寫鎖的流程

protected final int tryAcquireShared(int unused) {
 ? ?// 獲取到當(dāng)前線程對(duì)象
 ? ?Thread current = Thread.currentThread();
 ? ?// 獲取到當(dāng)前狀態(tài)值
 ? ?int c = getState();
 ? ?if (exclusiveCount(c) != 0 && // 有沒有線程持有寫鎖
 ? ? ? ?getExclusiveOwnerThread() != current) // 如果有線程獲取到了互斥鎖,那么進(jìn)一步看看是不是當(dāng)前線程
 ? ? ? ?// 不是當(dāng)前線程,那么直接返回-1,告訴AQS獲取共享鎖失敗
 ? ? ? ?return -1;
 ? ?// 獲取到讀鎖的持有數(shù)量
 ? ?int r = sharedCount(c);
 ? ?if (!readerShouldBlock() && // 讓子類來判定當(dāng)前獲取讀鎖的線程是否應(yīng)該被阻塞
 ? ? ? ?r < MAX_COUNT && // 判斷是否發(fā)生了溢出
 ? ? ? ?compareAndSetState(c, c + SHARED_UNIT)) { // 直接CAS 增加state的高16位的讀鎖持有數(shù)量
 ? ? ? ?// 增加高16位之前的計(jì)數(shù)為0,此時(shí)表明當(dāng)前線程就是第一個(gè)獲取讀鎖的線程
 ? ? ? ?if (r == 0) {
 ? ? ? ? ? ?// 注意:持有兩個(gè)變量來優(yōu)化threadlocal 
 ? ? ? ? ? ?firstReader = current;
 ? ? ? ? ? ?firstReaderHoldCount = 1;
 ? ? ?  } else if (firstReader == current) {
 ? ? ? ? ? ?// 當(dāng)前獲取讀鎖的線程就是一個(gè)線程,那么此時(shí)表明:鎖重入,直接++計(jì)數(shù)位即可
 ? ? ? ? ? ?firstReaderHoldCount++;
 ? ? ?  } else {
 ? ? ? ? ? ?// 當(dāng)前線程不是第一個(gè)讀線程,此時(shí)將其獲取讀鎖的次數(shù)保存在ThreadLocal中
 ? ? ? ? ? ?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;
 ?  }
 ? ?// 有很多同學(xué)走到這里,直接懵逼?不知道這是啥情況?經(jīng)驗(yàn):在看doug lea寫的代碼時(shí),請(qǐng)注意:經(jīng)常做優(yōu)化,就是把一些常見的場(chǎng)景前置,保證性能
 ? ?return fullTryAcquireShared(current);
}

fullTryAcquireShared完全獲取讀鎖流程

final int fullTryAcquireShared(Thread current) {
 ? ?HoldCounter rh = null;
 ? ?for (;;) {
 ? ? ? ?int c = getState();
 ? ? ? ?// 當(dāng)前已經(jīng)有線程獲取到寫鎖且當(dāng)前獲取寫鎖的線程不是,當(dāng)前線程
 ? ? ? ?if (exclusiveCount(c) != 0) {
 ? ? ? ? ? ?if (getExclusiveOwnerThread() != current)
 ? ? ? ? ? ? ? ?return -1;
 ? ? ?  } else if (readerShouldBlock()) {
 ? ? ? ? ? ?// 子類判斷當(dāng)前線程應(yīng)該阻塞
 ? ? ? ? ? ?if (firstReader == current) {
 ? ? ? ? ? ? ? ?// 當(dāng)前線程就是第一個(gè)獲取到讀鎖的線程
 ? ? ? ? ?  } else {
 ? ? ? ? ? ? ? ?// 獲取到當(dāng)前線程記錄讀鎖重入次數(shù)的HoldCounter對(duì)象
 ? ? ? ? ? ? ? ?if (rh == null) {
 ? ? ? ? ? ? ? ? ? ?rh = cachedHoldCounter;
 ? ? ? ? ? ? ? ? ? ?if (rh == null || rh.tid != getThreadId(current)) {
 ? ? ? ? ? ? ? ? ? ? ? ?rh = readHolds.get();
 ? ? ? ? ? ? ? ? ? ? ? ?if (rh.count == 0)
 ? ? ? ? ? ? ? ? ? ? ? ? ? ?readHolds.remove();
 ? ? ? ? ? ? ? ? ?  }
 ? ? ? ? ? ? ?  }
 ? ? ? ? ? ? ? ?// 當(dāng)前讀鎖重入次數(shù)為0時(shí),表明沒有獲取讀鎖,此時(shí)返回-1,阻塞當(dāng)前線程
 ? ? ? ? ? ? ? ?if (rh.count == 0)
 ? ? ? ? ? ? ? ? ? ?return -1;
 ? ? ? ? ?  }
 ? ? ?  }
 ? ? ? ?// 讀鎖獲取次數(shù)溢出
 ? ? ? ?if (sharedCount(c) == MAX_COUNT)
 ? ? ? ? ? ?throw new Error("Maximum lock count exceeded");
 ? ? ? ?// CAS增加讀鎖次數(shù)
 ? ? ? ?if (compareAndSetState(c, c + SHARED_UNIT)) {
 ? ? ? ? ? ?if (sharedCount(c) == 0) {
 ? ? ? ? ? ? ? ?firstReader = current;
 ? ? ? ? ? ? ? ?firstReaderHoldCount = 1;
 ? ? ? ? ?  } else if (firstReader == current) {
 ? ? ? ? ? ? ? ?firstReaderHoldCount++;
 ? ? ? ? ?  } else {
 ? ? ? ? ? ? ? ?if (rh == null)
 ? ? ? ? ? ? ? ? ? ?rh = cachedHoldCounter;
 ? ? ? ? ? ? ? ?if (rh == null || rh.tid != getThreadId(current))
 ? ? ? ? ? ? ? ? ? ?rh = readHolds.get();
 ? ? ? ? ? ? ? ?else if (rh.count == 0)
 ? ? ? ? ? ? ? ? ? ?readHolds.set(rh);
 ? ? ? ? ? ? ? ?rh.count++;
 ? ? ? ? ? ? ? ?cachedHoldCounter = rh;
 ? ? ? ? ?  }
 ? ? ? ? ? ?return 1;
 ? ? ?  }
 ?  }
}

tryRelease釋放寫鎖的流程

protected final boolean tryRelease(int releases) {
 ? ?// 沒有獲取寫鎖,為啥能釋放寫鎖呢?
 ? ?if (!isHeldExclusively())
 ? ? ? ?throw new IllegalMonitorStateException();
 ? ?int nextc = getState() - releases;
 ? ?// 釋放完畢后,寫鎖狀態(tài)是否為0(鎖重入),因?yàn)榇藭r(shí)計(jì)算的不是當(dāng)前state,是nextc
 ? ?boolean free = exclusiveCount(nextc) == 0;
 ? ?// 如果下一個(gè)狀態(tài)值為0,此時(shí)表明當(dāng)前線程完全釋放了鎖,也即鎖重入為0,那么將當(dāng)前線程對(duì)象從OwnerThread中移除
 ? ?if (free)
 ? ? ? ?setExclusiveOwnerThread(null);
 ? ?// 此時(shí)設(shè)置全局state變量即可
 ? ?setState(nextc);
 ? ?// 如果返回為true,那么由AQS完成后面線程的喚醒
 ? ?return free;
}

tryReleaseShared釋放讀鎖的流程

釋放時(shí),需要考慮:重入多少次,就釋放多少次??偨Y(jié):先完成自己的釋放,然后再完成共享的高16位的釋放。

protected final boolean tryReleaseShared(int unused) {
 ? ?Thread current = Thread.currentThread();
 ? ?// 當(dāng)前線程是第一個(gè)獲取到讀鎖的線程
 ? ?if (firstReader == current) {
 ? ? ? ?// 當(dāng)前重入次數(shù)為1,代表什么?代表可以直接釋放,如果不是1,那么表明還持有多個(gè)讀鎖,也即重入多次,那么直接--
 ? ? ? ?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) {
 ? ? ? ? ? ?// 當(dāng)前線程已經(jīng)釋放完讀鎖,那么不需要在ThreadLocal里持有HoldCounter對(duì)象
 ? ? ? ? ? ?readHolds.remove();
 ? ? ? ? ? ?if (count <= 0)
 ? ? ? ? ? ? ? ?throw unmatchedUnlockException();
 ? ? ?  }
 ? ? ? ?--rh.count;
 ?  }
 ? ?for (;;) {
 ? ? ? ?// CAS釋放高16位計(jì)數(shù)
 ? ? ? ?int c = getState();
 ? ? ? ?int nextc = c - SHARED_UNIT;
 ? ? ? ?if (compareAndSetState(c, nextc))
 ? ? ? ? ? ?// 釋放完畢后是否為0,為無鎖狀態(tài),此時(shí)需要干啥?由AQS來喚醒阻塞的線程
 ? ? ? ? ? ?return nextc == 0;
 ?  }
}

readerShouldBlock和writerShouldBlock模板方法公平鎖實(shí)現(xiàn)

判斷條件只有一個(gè):hasQueuedPredecessors()方法,就是看看AQS的阻塞隊(duì)列里是否有其他線程正在等待,如果有排隊(duì)去。

總結(jié):有人在排隊(duì),那么不插隊(duì)。w->r->r->r 此時(shí)來了個(gè)r:w->r->r->r->r, 此時(shí)來了個(gè)w:w->r->r->r->w。

static final class FairSync extends Sync {
 ? ?final boolean writerShouldBlock() {
 ? ? ? ?return hasQueuedPredecessors();
 ?  }
 ? ?final boolean readerShouldBlock() {
 ? ? ? ?return hasQueuedPredecessors();
 ?  } // w->r->r ? r獲取鎖  w->r->r-r
}

readerShouldBlock和writerShouldBlock模板方法非公平鎖實(shí)現(xiàn)

寫線程永遠(yuǎn)false,因?yàn)樽x寫鎖本身適用的是讀多寫少,此時(shí)不應(yīng)該 讓寫線程饑餓,而且非公平,寫鎖永遠(yuǎn)不阻塞,讓它搶,不管前面是否有人排隊(duì),先搶了再說。apparentlyFirstQueuedIsExclusive()第一個(gè)排隊(duì)的是不是寫線程。r(10),當(dāng)前線程是第十一個(gè),此時(shí)已經(jīng)有一個(gè)寫線程排隊(duì),r(10)->w,此時(shí)排隊(duì)去。r(10)->w->r。

static final class NonfairSync extends Sync {
 ? ?final boolean writerShouldBlock() {
 ? ? ? ?return false;
 ?  }
 ? ?final boolean readerShouldBlock() {
 ? ? ? ?return apparentlyFirstQueuedIsExclusive();
 ?  } // w->r->r ? r獲取鎖  r->r->r
}

到此這篇關(guān)于Java中ReentrantLock和ReentrantReadWriteLock的原理的文章就介紹到這了,更多相關(guān)Java ReentrantLock內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 一個(gè)簡(jiǎn)易的Java多頁(yè)面隊(duì)列爬蟲程序

    一個(gè)簡(jiǎn)易的Java多頁(yè)面隊(duì)列爬蟲程序

    這篇文章主要為大家詳細(xì)介紹了一個(gè)多頁(yè)面的java爬蟲,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-08-08
  • Java基礎(chǔ)教程之整數(shù)運(yùn)算

    Java基礎(chǔ)教程之整數(shù)運(yùn)算

    Java的整數(shù)運(yùn)算與C語(yǔ)言相同,遵循四則運(yùn)算規(guī)則,下面這篇文章主要給大家介紹了關(guān)于Java基礎(chǔ)教程之整數(shù)運(yùn)算的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-03-03
  • Windows系統(tǒng)編寫bat腳本啟動(dòng)、停止及重啟Java服務(wù)jar包

    Windows系統(tǒng)編寫bat腳本啟動(dòng)、停止及重啟Java服務(wù)jar包

    在bat文件中我們將編寫一些代碼來運(yùn)行Java jar文件,下面這篇文章主要給大家介紹了關(guān)于Windows系統(tǒng)編寫bat腳本啟動(dòng)、停止及重啟Java服務(wù)jar包的相關(guān)資料,需要的朋友可以參考下
    2023-12-12
  • SpringBoot2使用Jetty容器操作(替換默認(rèn)Tomcat)

    SpringBoot2使用Jetty容器操作(替換默認(rèn)Tomcat)

    這篇文章主要介紹了SpringBoot2使用Jetty容器操作(替換默認(rèn)Tomcat),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-10-10
  • 一文帶你探索Java中的通配符與泛型

    一文帶你探索Java中的通配符與泛型

    Java 語(yǔ)言中的泛型是一種強(qiáng)大的特性,它可以將類型參數(shù)化,使得代碼更具通用性和安全性,本文將深入講解 Java 通配符和泛型,有需要的小伙伴可以了解下
    2023-12-12
  • Java線程池實(shí)現(xiàn)原理總結(jié)

    Java線程池實(shí)現(xiàn)原理總結(jié)

    這篇文章主要給大家分享的是Java線程池實(shí)現(xiàn)原理總結(jié),線程池參數(shù)、線程池執(zhí)行流程等內(nèi)容上總結(jié),具有一定參考戒指,需要的小伙伴可以參考一下,希望對(duì)你有所幫助
    2022-01-01
  • SpringBoot集成Redis流程詳解

    SpringBoot集成Redis流程詳解

    這篇文章主要介紹了SpringBoot集成Redis流程詳解,導(dǎo)入jar包,編寫配置類,編寫util類,配置yml這四個(gè)步驟,有詳細(xì)的代碼示例,,需要的朋友可以參考下
    2023-05-05
  • Java實(shí)現(xiàn)驗(yàn)證碼驗(yàn)證功能

    Java實(shí)現(xiàn)驗(yàn)證碼驗(yàn)證功能

    Java如何實(shí)現(xiàn)驗(yàn)證碼驗(yàn)證功能呢?日常生活中,驗(yàn)證碼隨處可見,他可以在一定程度上保護(hù)賬號(hào)安全,那么他是怎么實(shí)現(xiàn)的呢?今天通過本文給大家實(shí)例詳解,需要的朋友參考下
    2017-02-02
  • Java 判斷字符串中是否包含中文的實(shí)例詳解

    Java 判斷字符串中是否包含中文的實(shí)例詳解

    這篇文章主要介紹了Java 判斷字符串中是否包含中文的實(shí)例詳解的相關(guān)資料,這里提供實(shí)例來說明該如何實(shí)現(xiàn)這樣的功能,需要的朋友可以參考下
    2017-08-08
  • SpringBoot啟動(dòng)報(bào)錯(cuò)屬性循環(huán)依賴報(bào)錯(cuò)問題的解決

    SpringBoot啟動(dòng)報(bào)錯(cuò)屬性循環(huán)依賴報(bào)錯(cuò)問題的解決

    這篇文章主要介紹了SpringBoot啟動(dòng)報(bào)錯(cuò)屬性循環(huán)依賴報(bào)錯(cuò)問題的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-05-05

最新評(píng)論