最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中ReentrantLock和ReentrantReadWriteLock的原理

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

ReentrantLock 原理

概念

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

核心變量和構造器

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

核心方法

獲取鎖操作:

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

釋放鎖操作:

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

ReentrantReadWriteLock 原理

用例

將原來的鎖,分割為兩把鎖:讀鎖、寫鎖。適用于讀多寫少的場景,讀鎖可以并發(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();
 ?  }
}

核心變量和構造器

該接口用于獲取讀鎖和寫鎖對象

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

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

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

Sync類

核心變量和構造器

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

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

tryAcquire獲取寫鎖的流程

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

protected final boolean tryAcquire(int acquires) {
 ? ?// 獲取當前線程
 ? ?Thread current = Thread.currentThread();
 ? ?// 獲取當前狀態(tài)值和互斥鎖的數(shù)量
 ? ?int c = getState();
 ? ?int w = exclusiveCount(c);
 ? ?// 狀態(tài)值有效
 ? ?if (c != 0) {
 ? ? ? ?// 有線程獲取到了讀鎖或者當前線程不是持有互斥鎖的線程
 ? ? ? ?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() || // 由子類實現(xiàn)判斷當前線程是否應該獲取寫鎖
 ? ? ? ?!compareAndSetState(c, c + acquires)) // 通過CAS搶寫鎖
 ? ? ? ?return false;
 ? ?// 獲取寫鎖成功,那么將當前線程標識為獲取互斥鎖的線程對象
 ? ?setExclusiveOwnerThread(current);
 ? ?return true;
}

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

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

fullTryAcquireShared完全獲取讀鎖流程

final int fullTryAcquireShared(Thread current) {
 ? ?HoldCounter rh = null;
 ? ?for (;;) {
 ? ? ? ?int c = getState();
 ? ? ? ?// 當前已經(jīng)有線程獲取到寫鎖且當前獲取寫鎖的線程不是,當前線程
 ? ? ? ?if (exclusiveCount(c) != 0) {
 ? ? ? ? ? ?if (getExclusiveOwnerThread() != current)
 ? ? ? ? ? ? ? ?return -1;
 ? ? ?  } else if (readerShouldBlock()) {
 ? ? ? ? ? ?// 子類判斷當前線程應該阻塞
 ? ? ? ? ? ?if (firstReader == current) {
 ? ? ? ? ? ? ? ?// 當前線程就是第一個獲取到讀鎖的線程
 ? ? ? ? ?  } else {
 ? ? ? ? ? ? ? ?// 獲取到當前線程記錄讀鎖重入次數(shù)的HoldCounter對象
 ? ? ? ? ? ? ? ?if (rh == null) {
 ? ? ? ? ? ? ? ? ? ?rh = cachedHoldCounter;
 ? ? ? ? ? ? ? ? ? ?if (rh == null || rh.tid != getThreadId(current)) {
 ? ? ? ? ? ? ? ? ? ? ? ?rh = readHolds.get();
 ? ? ? ? ? ? ? ? ? ? ? ?if (rh.count == 0)
 ? ? ? ? ? ? ? ? ? ? ? ? ? ?readHolds.remove();
 ? ? ? ? ? ? ? ? ?  }
 ? ? ? ? ? ? ?  }
 ? ? ? ? ? ? ? ?// 當前讀鎖重入次數(shù)為0時,表明沒有獲取讀鎖,此時返回-1,阻塞當前線程
 ? ? ? ? ? ? ? ?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(鎖重入),因為此時計算的不是當前state,是nextc
 ? ?boolean free = exclusiveCount(nextc) == 0;
 ? ?// 如果下一個狀態(tài)值為0,此時表明當前線程完全釋放了鎖,也即鎖重入為0,那么將當前線程對象從OwnerThread中移除
 ? ?if (free)
 ? ? ? ?setExclusiveOwnerThread(null);
 ? ?// 此時設置全局state變量即可
 ? ?setState(nextc);
 ? ?// 如果返回為true,那么由AQS完成后面線程的喚醒
 ? ?return free;
}

tryReleaseShared釋放讀鎖的流程

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

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

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

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

總結(jié):有人在排隊,那么不插隊。w->r->r->r 此時來了個r:w->r->r->r->r, 此時來了個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模板方法非公平鎖實現(xiàn)

寫線程永遠false,因為讀寫鎖本身適用的是讀多寫少,此時不應該 讓寫線程饑餓,而且非公平,寫鎖永遠不阻塞,讓它搶,不管前面是否有人排隊,先搶了再說。apparentlyFirstQueuedIsExclusive()第一個排隊的是不是寫線程。r(10),當前線程是第十一個,此時已經(jīng)有一個寫線程排隊,r(10)->w,此時排隊去。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
}

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

相關文章

  • SpringBoot中驗證用戶上傳的圖片資源的方法

    SpringBoot中驗證用戶上傳的圖片資源的方法

    這篇文章主要介紹了在SpringBoot中驗證用戶上傳的圖片資源,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-09-09
  • Java8?lambda表達式的10個實例講解

    Java8?lambda表達式的10個實例講解

    這篇文章主要介紹了Java8?lambda表達式的10個實例,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • springboot日期格式化及時差問題分析

    springboot日期格式化及時差問題分析

    這篇文章主要介紹了springboot日期格式化,時差問題,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-12-12
  • Nebula?Graph介紹和SpringBoot環(huán)境連接和查詢操作

    Nebula?Graph介紹和SpringBoot環(huán)境連接和查詢操作

    Nebula?Graph?是一款開源的、分布式的、易擴展的原生圖數(shù)據(jù)庫,能夠承載包含數(shù)千億個點和數(shù)萬億條邊的超大規(guī)模數(shù)據(jù)集,并且提供毫秒級查詢,這篇文章主要介紹了Nebula?Graph介紹和SpringBoot環(huán)境連接和查詢,需要的朋友可以參考下
    2022-10-10
  • 基于Springboot+Netty實現(xiàn)rpc的方法 附demo

    基于Springboot+Netty實現(xiàn)rpc的方法 附demo

    這篇文章主要介紹了基于Springboot+Netty實現(xiàn)rpc功能,在父項目中引入相關依賴結(jié)合實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-02-02
  • Java實現(xiàn)學生成績管理系統(tǒng)

    Java實現(xiàn)學生成績管理系統(tǒng)

    這篇文章主要為大家詳細介紹了Java實現(xiàn)學生成績管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-04-04
  • java 詳解類加載器的雙親委派及打破雙親委派

    java 詳解類加載器的雙親委派及打破雙親委派

    這篇文章主要介紹了java 詳解類加載器的雙親委派及打破雙親委派的相關資料,需要的朋友可以參考下
    2017-01-01
  • Springboot自定義mybatis攔截器實現(xiàn)擴展

    Springboot自定義mybatis攔截器實現(xiàn)擴展

    本文主要介紹了Springboot自定義mybatis攔截器實現(xiàn)擴展,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • java 中sendredirect()和forward()方法的區(qū)別

    java 中sendredirect()和forward()方法的區(qū)別

    這篇文章主要介紹了java 中sendredirect()和forward()方法的區(qū)別,需要的朋友可以參考下
    2017-08-08
  • java?環(huán)境配置(2023年詳細教程)

    java?環(huán)境配置(2023年詳細教程)

    這篇文章首先為了完善我的知識體系,今后一些軟件的安裝教程也可能會用到想寫一個更加詳細的,因為這并不僅僅是寫給?IT?行業(yè)的,其它行業(yè)可能也需要配置java環(huán)境
    2023-06-06

最新評論

哈密市| 临高县| 揭东县| 易门县| 新丰县| 科技| 观塘区| 禄丰县| 岳西县| 贵州省| 镇宁| 宝山区| 长寿区| 托里县| 翼城县| 分宜县| 台中县| 阿勒泰市| 巴东县| 嵩明县| 独山县| 重庆市| 周口市| 丹棱县| 博白县| 衡阳市| 醴陵市| 阿拉善右旗| 枝江市| 丽水市| 承德市| 杭锦旗| 赤水市| 枣阳市| 凤台县| 革吉县| 修水县| 固原市| 建始县| 东宁县| 田林县|