AQS之同步器

AQS之獨(dú)占鎖
AQS之共享鎖
AQS之Condition

在了解了AQS的實(shí)現(xiàn)原理之后再來看這些同步器會(huì)覺得很親切,這其實(shí)也是在告訴自己,基礎(chǔ)的重要性

ReentrantLock

Lock lock = new ReentrantLock();
for (int i = 0; i < 3; i++) {
    new Thread(() -> {
        lock.lock();
        System.out.println(Thread.currentThread().getName() + " " + LocalDateTime.now());
        sleep(TimeUnit.SECONDS, 2);
        lock.unlock();
    }).start();
}

---------------------------------執(zhí)行結(jié)果------------------------------------
Thread-0 2020-01-01T17:12:24.678
Thread-1 2020-01-01T17:12:26.681
Thread-2 2020-01-01T17:12:28.681
  1. 實(shí)現(xiàn)原理基于獨(dú)占鎖
  2. 公平鎖tryAcquire方法中會(huì)先判斷隊(duì)列中有沒有阻塞節(jié)點(diǎn),有就加入隊(duì)列,沒有就通過CAS嘗試獲取鎖
  3. 非公平鎖tryAcquire中不管隊(duì)列中有沒有阻塞節(jié)點(diǎn),直接先通過CAS嘗試獲取鎖,獲取成功就返回,獲取失敗就加入阻塞隊(duì)列

CountDownLatch

CountDownLatch countDownLatch = new CountDownLatch(3);
new Thread(() -> {
    sleep(TimeUnit.MILLISECONDS, 80);
    System.out.println(Thread.currentThread().getName() + " Finished");
    countDownLatch.countDown();
}).start();
new Thread(() -> {
    sleep(TimeUnit.MILLISECONDS, 50);
    System.out.println(Thread.currentThread().getName() + " Finished");
    countDownLatch.countDown();
}).start();
new Thread(() -> {
    sleep(TimeUnit.MILLISECONDS, 60);
    System.out.println(Thread.currentThread().getName() + " Finished");
    countDownLatch.countDown();
}).start();
new Thread(() -> {
    sleep(TimeUnit.MILLISECONDS, 60);
    System.out.println(Thread.currentThread().getName() + " Finished");
    countDownLatch.countDown();
}).start();
countDownLatch.await();
System.out.println("All Finished");


---------------------------------執(zhí)行結(jié)果------------------------------------
Thread-1 Finished
Thread-2 Finished
Thread-3 Finished
All Finished
Thread-0 Finished
  1. 實(shí)現(xiàn)原理基于共享鎖
  2. 在初始化的時(shí)候傳入一個(gè)變量,該變量即代表同步器中state的值
  3. 調(diào)用CountDownLatch#await方法的時(shí)候,會(huì)判斷state的值是否等于0,不等于0就添加到阻塞隊(duì)列,等于0就直接返回
  4. 調(diào)用CountDownLatch#countDown方法的時(shí)候,state減1,判斷state的值是否等于0,等于0就釋放因調(diào)用CountDownLatch#await方法而阻塞的線程,不等于0就直接返回

CyclicBarrier

CyclicBarrier cyclicBarrier = new CyclicBarrier(2, () -> System.out.println("阻塞解除之后執(zhí)行一些邏輯 " + LocalDateTime.now()));
for (int i = 0; i < 3; i++) {
    new Thread(() -> {
        try {
            System.out.println(Thread.currentThread().getName() + " doXX");
            cyclicBarrier.await();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }).start();

    new Thread(() -> {
        try {
            System.out.println(Thread.currentThread().getName() + " doXX");
            cyclicBarrier.await();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }).start();

    sleep(TimeUnit.SECONDS, 2);
}

---------------------------------執(zhí)行結(jié)果------------------------------------
Thread-0 doXX
Thread-1 doXX
阻塞解除之后執(zhí)行一些邏輯 2020-01-01T14:19:15.735
Thread-2 doXX
Thread-3 doXX
阻塞解除之后執(zhí)行一些邏輯 2020-01-01T14:19:17.706
Thread-4 doXX
Thread-5 doXX
阻塞解除之后執(zhí)行一些邏輯 2020-01-01T14:19:19.706

字面意思就是循環(huán)壁壘,使用上與CountDownLatch類似,不過實(shí)現(xiàn)上完全不一樣,CyclicBarrier統(tǒng)計(jì)的的是調(diào)用了CyclicBarrier#await方法的線程數(shù),當(dāng)線程數(shù)達(dá)到了CyclicBarrier初始時(shí)規(guī)定的數(shù)目時(shí),所有進(jìn)入等待狀態(tài)的線程將被喚醒然后進(jìn)入下一輪,可以重復(fù)使用

  1. 實(shí)現(xiàn)原理是基于ReentrantLockCondition
  2. 執(zhí)行CyclicBarrier#await之前,需要先執(zhí)行ReentrantLock#lock方法,完成之后執(zhí)行ReentrantLock#unlock方法,即通過ReentrantLock保證執(zhí)行CyclicBarrier#await方法是安全的
  3. 在執(zhí)行CyclicBarrier#await方法的時(shí)候,不滿足釋放條件(調(diào)用CyclicBarrier#await方法的線程數(shù)不等于初始值)時(shí),會(huì)調(diào)用Condition#await方法是當(dāng)前線程阻塞,滿足釋放條件時(shí)會(huì)調(diào)用Condition#signalAll喚醒所有阻塞的線程然后進(jìn)入下一輪
  4. CyclicBarrier中有一個(gè)內(nèi)部類Generation,該內(nèi)部類就表示一輪一輪循環(huán)的意思,當(dāng)滿足釋放條件時(shí),除了喚醒所有因調(diào)用CyclicBarrier#await方法而阻塞的線程,還會(huì)生成一個(gè)新的Generation對(duì)象,代表下一輪開始

Semaphore

信號(hào)量,可以用來控制同時(shí)訪問資源的線程個(gè)數(shù),比如可以用在對(duì)線程數(shù)的限流,在初始化的時(shí)候需要用戶傳入許可的數(shù)量,通過Semaphore#acquire方法獲取一個(gè)許可,如果Semaphore還有許可可獲取就直接返回,否則阻塞當(dāng)前線程

Semaphore semaphore = new Semaphore(2);
for (int i = 0; i < 4; i++) {
    new Thread(() -> {
        try {
            semaphore.acquire();
            System.out.println(Thread.currentThread().getName() + "訪問資源");
            sleep(TimeUnit.MILLISECONDS, 10 + new Random().nextInt(10));
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            System.out.println(Thread.currentThread().getName() + "釋放資源");
            semaphore.release();
        }

    }).start();
}

---------------------------------執(zhí)行結(jié)果------------------------------------
Thread-1訪問資源
Thread-0訪問資源
Thread-0釋放資源
Thread-2訪問資源
Thread-1釋放資源
Thread-3訪問資源
Thread-2釋放資源
Thread-3釋放資源
  1. 實(shí)現(xiàn)原理基于共享鎖
  2. 內(nèi)部類Sync實(shí)現(xiàn)了AbstractQueuedSynchronizer,Sync實(shí)現(xiàn)類有兩個(gè),對(duì)應(yīng)公平鎖和非公平鎖
  3. 簡(jiǎn)單來講, Semaphore其實(shí)就是一個(gè)共享鎖,根據(jù)我們對(duì)共享鎖的了解,共享鎖表示同一時(shí)刻最多有多少個(gè)線程持有鎖,這和Semaphore的特性是一致的,所以Semaphore只需要再封裝一層API,調(diào)用Semaphore#acquire方法時(shí)候獲取鎖或阻塞,調(diào)用,調(diào)用Semaphore#release`通過自旋釋放鎖就可以了

DelayQueue

  1. 實(shí)現(xiàn)原理基于ReentrantLockCondition
  2. 優(yōu)先級(jí) 無界 阻塞隊(duì)列
  3. 元素必須實(shí)現(xiàn)Delayed接口,Delayed#getDelay方法返回值<=0代表該元素延遲時(shí)間已到,可以出隊(duì)了
  4. 基于 優(yōu)先級(jí) 保證元素插入的順序,基于Delayed#getDelay來控制元素延遲的時(shí)間,基于Condition控制在獲取元素時(shí)是阻塞還是返回(隊(duì)首元素)

LinkedBlockingQueue

  1. 實(shí)現(xiàn)原理基于2個(gè)ReentrantLock和2個(gè)Condition,分別為ReentrantLock存取鎖Condition存取鎖
  2. 有界 阻塞隊(duì)列,如果不指定,容量默認(rèn)為Integer.MAX_VALUE
  3. 鏈表結(jié)構(gòu),每個(gè)元素會(huì)被封裝成一個(gè)Node節(jié)點(diǎn),每個(gè)Node節(jié)點(diǎn)有一個(gè)next指針
  4. 尾進(jìn)頭出,添加元素的時(shí)候放到尾部,獲取元素的時(shí)候放到頭部

添加元素

涉及到的方法:LinkedBlockingQueue#put,LinkedBlockingQueue#offer,如果隊(duì)列滿了,前者會(huì)阻塞,后者不會(huì)阻塞

  1. 先獲取ReentrantLock存鎖
  2. 如果已經(jīng)達(dá)到容量上限,就通過Condition存鎖阻塞當(dāng)前線程,否則添加元素
  3. 入隊(duì),將當(dāng)前元素添加到隊(duì)尾,將上次隊(duì)位元素的next指針指向該元素,更新last指向
  4. 容量加1,如果容量==0,喚醒Condition寫鎖

獲取元素

涉及到的方法:LinkedBlockingQueue#take,LinkedBlockingQueue#poll,如果隊(duì)列空了,前者會(huì)阻塞,后者不會(huì)阻塞

  1. 先獲取ReentrantLock寫鎖
  2. 如果隊(duì)列里面沒有元素,就通過Condition寫鎖阻塞當(dāng)前線程,否則獲取元素
  3. 出隊(duì),從隊(duì)首去取出一個(gè)元素,更新head指向
  4. 容量減1,如果容量滿了,喚醒Condition讀鎖

ArrayBlockingQueue

  1. 實(shí)現(xiàn)原理基于1個(gè)ReentrantLock和2個(gè)Condition,兩個(gè)Condition分別用于判斷是否為空和是否已滿
  2. 有界 阻塞隊(duì)列,基于final數(shù)組,自然是有界的
  3. 數(shù)組結(jié)構(gòu),基于final數(shù)組,,在初始化ArrayBlockingQueue的時(shí)候需要指定容量

添加元素

涉及到的方法:ArrayBlockingQueue#put,ArrayBlockingQueue#offer,如果隊(duì)列滿了,前者會(huì)阻塞,后者不會(huì)阻塞

  1. 獲取ReentrantLock
  2. 如果隊(duì)列滿了,通過判斷是否已滿的Condition阻塞當(dāng)前線程
  3. 有一個(gè)變量putIndex用于記錄下次添加元素時(shí)對(duì)應(yīng)的數(shù)組下標(biāo),當(dāng)takeIndex==隊(duì)列.length的時(shí)候,重置該變量為0
  4. 喚醒判斷是否為空的Condition

獲取元素

涉及到的方法:ArrayBlockingQueue#take,ArrayBlockingQueue#poll,如果隊(duì)列空了,前者會(huì)阻塞,后者不會(huì)阻塞

  1. 獲取ReentrantLock
  2. 如果隊(duì)列為空了,通過判斷是否為空的Condition阻塞當(dāng)前線程
  3. 有一個(gè)變量takeIndex用于記錄下次獲取元素時(shí)對(duì)應(yīng)的數(shù)組下標(biāo),當(dāng)takeIndex==隊(duì)列.length的時(shí)候,重置該變量為0
  4. 喚醒判斷是否已滿的Condition

LinkedTransferQueue

進(jìn)行線程間數(shù)據(jù)交換的利器 todo

SynchronousQueue

PriorityBlockingQueue

  1. 實(shí)現(xiàn)原理基于ReentrantLockCondition
  2. 優(yōu)先級(jí) 無界 阻塞隊(duì)列,優(yōu)先級(jí)的實(shí)現(xiàn)基于二叉堆
  3. 值不允許null,且需要實(shí)現(xiàn)Comparable接口

優(yōu)先級(jí)的 無界阻塞隊(duì)列,優(yōu)先級(jí)可以基于自然排序,也可以基于Comparable接口,取決于你使用哪個(gè)構(gòu)造函數(shù)

添加元素

涉及到的方法: PriorityBlockingQueue#add PriorityBlockingQueue#offer

  1. 先通過ReentrantLock獲取鎖
  2. 判斷size >= queue.length,如果條件成立就擴(kuò)容
    3.通過Comparable#二叉堆便利找到合適的位置插入元素
  3. size加1
  4. 喚醒因執(zhí)行了PriorityBlockingQueue#take方法而阻塞的線程(即隊(duì)列中沒有元素的時(shí)候),這個(gè)通過Condition實(shí)現(xiàn)
  5. 釋放鎖

獲取元素

涉及到的方法: PriorityBlockingQueue#poll PriorityBlockingQueue#take

  1. 在調(diào)用這些方法之前都需要先通過ReentrantLock獲取鎖
  2. PriorityBlockingQueue#poll方法,在隊(duì)列中沒有元素的時(shí)候直接返回null,不會(huì)阻塞當(dāng)前線程
  3. PriorityBlockingQueue#take方法,在隊(duì)列中沒有元素的時(shí)候會(huì)阻塞當(dāng)前線程,知道隊(duì)列中有元素然后再被喚醒返回,基于Condition實(shí)現(xiàn)

隊(duì)列擴(kuò)容

涉及到的方法: PriorityBlockingQueue#tryGrow

  1. 執(zhí)行ReentrantLock#unlock方法,釋放ReentrantLock鎖,為什么要釋放這個(gè)鎖呢?我猜這里是為了提高性能,在擴(kuò)容之前先釋放鎖,然后通過一個(gè)CAS變量來控制擴(kuò)容的并發(fā)問題,這樣在擴(kuò)容期間就不會(huì)接阻塞其他調(diào)用線程,比如take操作,很妙
  2. 當(dāng)前是否正在擴(kuò)容通過一個(gè)volatile變量表示,0表示目前不在擴(kuò)容,1表示正在擴(kuò)容,每次擴(kuò)容之前通過CAS將其設(shè)置為1,如果CAS失敗說明目前有其他線程正在擴(kuò)容,此時(shí)不做處理
  3. 擴(kuò)容的時(shí)候先判斷當(dāng)前容量是否小于64,如果小于64就對(duì)容量*2+2;如果不小于64,則對(duì)容量*1.5
  4. 重新基于該容量創(chuàng)建一個(gè)新的Object[]
  5. 如果有并發(fā)問題,就通過Thread#yield讓出當(dāng)前CPU
  6. 通過System#arraycopy對(duì)行隊(duì)列賦值,在賦值之前需要先通過ReentrantLock#lock再次獲取鎖

CopyOnWriteArrayList

可以將它看成是一個(gè)線程安全的ArrayList,在涉及到修改操作時(shí),通過ReentrantLock獲取鎖,然后復(fù)制一個(gè)新的數(shù)組去修改,基于volatile語義可以讀數(shù)據(jù)時(shí)不會(huì)有問題,適用于讀多寫少的場(chǎng)景,如果寫比較多的比較影響性能

  1. 實(shí)現(xiàn)原理基于ReentrantLockvolatile
  2. 元素可以為null

獲取元素

例如CopyOnWriteArrayList#get方法,直接返回?cái)?shù)組下標(biāo)對(duì)應(yīng)的元素即可

修改元素

例如CopyOnWriteArrayList#set CopyOnWriteArrayList#add`方法

  1. 先獲取ReentrantLock
  2. 基于原數(shù)組創(chuàng)建一個(gè)新的數(shù)組,然后使引用指向新數(shù)組
  3. 釋放鎖

CopyOnWriteArraySet

內(nèi)部持有一個(gè)CopyOnWriteArrayList引用,也就是它的實(shí)現(xiàn)完全是基于CopyOnWriteArrayList,那它是如何保證元素不唯一呢?在CopyOnWriteArrayList中有一個(gè)addIfAbsent方法,該方法會(huì)通過遍歷的方式去判斷你要添加的元素是否存在.

適合讀多寫少的場(chǎng)景

ReentrantReadWriteLock

  1. 持有寫鎖的時(shí)候不能申請(qǐng)讀鎖,持有讀鎖的時(shí)候不能申請(qǐng)寫鎖,但鎖降級(jí)的時(shí)候是個(gè)例外(持有寫鎖的情況下降級(jí)成讀鎖,實(shí)際上是持有寫鎖的時(shí)候再去申請(qǐng)讀鎖,因?yàn)槎际潜煌粋€(gè)線程占有,所以不會(huì)有問題)
  2. 寫鎖,獨(dú)占鎖,int類型低16位表示,當(dāng)一個(gè)線程持有寫鎖的時(shí)候,其它線程不能獲取讀鎖,只能在阻塞隊(duì)列排隊(duì),寫鎖可以降級(jí)成讀鎖
  3. 讀鎖,共享鎖,int類型高16位表示,當(dāng)一個(gè)線程持有讀鎖的時(shí)候,其他線程還可以申請(qǐng)讀鎖,但不能申請(qǐng)寫鎖,讀鎖不可以降級(jí)成寫鎖

使用示例

StringBuilder data = new StringBuilder("data");
ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();

new Thread((() -> {
    // sleep一會(huì),讓寫鎖先持有鎖
    sleep(TimeUnit.MILLISECONDS, 10);

    readWriteLock.readLock().lock();
    System.out.println(Thread.currentThread().getName() + "獲得讀鎖 " + LocalDateTime.now());
    System.out.println(Thread.currentThread().getName() + data);
    readWriteLock.readLock().unlock();
}), "readLock ").start();

new Thread((() -> {
    readWriteLock.writeLock().lock();
    System.out.println(Thread.currentThread().getName() + "獲得寫鎖 " + LocalDateTime.now());
    sleep(TimeUnit.SECONDS, 3);
    data.append("666");

    // 鎖降級(jí) 這里這樣子使用降級(jí)感覺沒有什么意思,那鎖降級(jí)一般用到什么場(chǎng)景
    readWriteLock.readLock().lock();
    System.out.println(Thread.currentThread().getName() + data);

    readWriteLock.writeLock().unlock();
}), "writeLock ").start();

構(gòu)造函數(shù)

public ReentrantReadWriteLock() {
    this(false);
}

// 可以在創(chuàng)建ReentrantReadWriteLock時(shí)選擇公平模式還是非公平模式
public ReentrantReadWriteLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
    readerLock = new ReadLock(this);
    writerLock = new WriteLock(this);
}
  1. 可以在創(chuàng)建ReentrantReadWriteLock時(shí)選擇使用公平鎖還是非公平鎖
  2. 內(nèi)部類Sync繼承自AbstractQueuedSynchronizer,它負(fù)責(zé)實(shí)現(xiàn)同步器的模板方法,是實(shí)現(xiàn)同步器的關(guān)鍵
  3. ReadLockWriteLock實(shí)現(xiàn)了Lock接口,可以將它們看作是API層,具體邏輯委托給Sync實(shí)現(xiàn),面向用戶

Sync

static final int SHARED_SHIFT   = 16;
static final int SHARED_UNIT    = (1 << SHARED_SHIFT);
static final int MAX_COUNT      = (1 << SHARED_SHIFT) - 1;
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;

/** Returns the number of shared holds represented in count  */
static int sharedCount(int c)    { return c >>> SHARED_SHIFT; }

/** Returns the number of exclusive holds represented in count  */
static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }

獲取讀鎖

public void lock() {
    sync.acquireShared(1);
}

public final void acquireShared(int arg) {
    if (tryAcquireShared(arg) < 0)
        doAcquireShared(arg);
}

protected final int tryAcquireShared(int unused) {
    Thread current = Thread.currentThread();
    int c = getState();

    // 其實(shí)這里就涉及到鎖降級(jí),如果當(dāng)前已經(jīng)有寫鎖,返回-1,將它加入到阻塞隊(duì)列, 否則繼續(xù)嘗試獲取讀鎖
    if (exclusiveCount(c) != 0 && getExclusiveOwnerThread() != current)
        return -1;

    int r = sharedCount(c);
    // readerShouldBlock主要是針對(duì)公平鎖和非公平鎖, `c + SHARED_UNIT`是因?yàn)楣蚕礞i用的是高16位
    if (!readerShouldBlock() && r < MAX_COUNT && compareAndSetState(c, c + SHARED_UNIT)) {
        if (r == 0) {
            // firstReader是把讀鎖狀態(tài)從0變成1的那個(gè)線程
            firstReader = current;
            firstReaderHoldCount = 1;
        } else if (firstReader == current) {
            // 鎖重入
            firstReaderHoldCount++;
        } else {
            // cachedHoldCounter是上一個(gè)獲取鎖成功的線程
            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;
    }

    // 上面的if失敗了,即通過自旋獲取鎖
    return fullTryAcquireShared(current);
}
final int fullTryAcquireShared(Thread current) {
    HoldCounter rh = null;
    for (;;) {
        int c = getState();
        if (exclusiveCount(c) != 0) {
            if (getExclusiveOwnerThread() != current)
                return -1;
            // else we hold the exclusive lock; blocking here
            // would cause deadlock.
        } else if (readerShouldBlock()) {
            // Make sure we're not acquiring read lock reentrantly
            if (firstReader == current) {
                // assert firstReaderHoldCount > 0;
            } else {
                if (rh == null) {
                    rh = cachedHoldCounter;
                    if (rh == null || rh.tid != getThreadId(current)) {
                        rh = readHolds.get();
                        if (rh.count == 0)
                            readHolds.remove();
                    }
                }
                if (rh.count == 0)
                    return -1;
            }
        }
        if (sharedCount(c) == MAX_COUNT)
            throw new Error("Maximum lock count exceeded");
        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; // cache for release
            }
            return 1;
        }
    }
}

釋放讀鎖

public final boolean releaseShared(int arg) {
    if (tryReleaseShared(arg)) {
        doReleaseShared();
        return true;
    }
    return false;
}

protected final boolean tryReleaseShared(int unused) {
    Thread current = Thread.currentThread();

    // 如果 firstReader 是當(dāng)前線程
    if (firstReader == current) {
        // assert firstReaderHoldCount > 0;

        // 并且firstReaderHoldCount == 1,說明釋放鎖之后需要重置firstReader
        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;
    }
}
  1. 讀鎖和寫鎖不能同時(shí)使用,所以釋放讀鎖的時(shí)候按理來說并不需要去喚醒節(jié)點(diǎn)
  2. 但如果state==0,需要喚醒阻塞的寫鎖

獲取寫鎖

protected final boolean tryAcquire(int acquires) {
    Thread current = Thread.currentThread();
    int c = getState();
    int w = exclusiveCount(c);

    // state != 0 && w==0 說明有讀鎖
    if (c != 0) {
        // (Note: if c != 0 and w == 0 then shared count != 0)
        if (w == 0 || current != getExclusiveOwnerThread())
            return false;

        if (w + exclusiveCount(acquires) > MAX_COUNT)
            throw new Error("Maximum lock count exceeded");

        // Reentrant acquire  鎖重入
        setState(c + acquires);
        return true;
    }

    // writerShouldBlock用于確定公平和非公平模式
    if (writerShouldBlock() ||
        !compareAndSetState(c, c + acquires))
        return false;
    setExclusiveOwnerThread(current);
    return true;
}

判斷是又讀鎖,判斷是否鎖重入,通過CAS設(shè)置狀態(tài)

釋放寫鎖

protected final boolean tryRelease(int releases) {
    if (!isHeldExclusively())
        throw new IllegalMonitorStateException();

    int nextc = getState() - releases;
    boolean free = exclusiveCount(nextc) == 0;
    if (free)
        setExclusiveOwnerThread(null);
    setState(nextc);
    return free;
}

和正常的獨(dú)占鎖釋放一樣

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市喘落,隨后出現(xiàn)的幾起案子瘪板,更是在濱河造成了極大的恐慌,老刑警劉巖符衔,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡迫肖,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門攒驰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蟆湖,“玉大人,你說我怎么就攤上這事玻粪∮缃颍” “怎么了诬垂?”我有些...
    開封第一講書人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長伦仍。 經(jīng)常有香客問我结窘,道長,這世上最難降的妖魔是什么充蓝? 我笑而不...
    開封第一講書人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任隧枫,我火速辦了婚禮,結(jié)果婚禮上谓苟,老公的妹妹穿的比我還像新娘官脓。我一直安慰自己,他們只是感情好涝焙,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開白布卑笨。 她就那樣靜靜地躺著,像睡著了一般仑撞。 火紅的嫁衣襯著肌膚如雪赤兴。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評(píng)論 1 297
  • 那天派草,我揣著相機(jī)與錄音搀缠,去河邊找鬼。 笑死近迁,一個(gè)胖子當(dāng)著我的面吹牛艺普,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播鉴竭,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼歧譬,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了搏存?” 一聲冷哼從身側(cè)響起瑰步,我...
    開封第一講書人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎璧眠,沒想到半個(gè)月后缩焦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡责静,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年袁滥,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片灾螃。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡题翻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出腰鬼,到底是詐尸還是另有隱情嵌赠,我是刑警寧澤塑荒,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站姜挺,受9級(jí)特大地震影響齿税,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜初家,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一偎窘、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧溜在,春花似錦陌知、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至志笼,卻和暖如春沿盅,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背纫溃。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來泰國打工腰涧, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人紊浩。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓窖铡,卻偏偏與公主長得像,于是被迫代替她去往敵國和親坊谁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子费彼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353