ReentrantReadWriteLock

ReentrantReadWriteLock.png
456af507-f0aa-4b02-afbd-1d137c239245.png

WriteLock

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

tryAcquire

protected final boolean tryAcquire(int acquires) {
    Thread current = Thread.currentThread();
    int c = getState();
    int w = exclusiveCount(c);
    if (c != 0) {
        // (Note: if c != 0 and w == 0 then shared count != 0)
        // c不等0,w等于0,说明现在有人持有读锁,所以写锁拿不到
        // 就算有人持有写锁,如果是别人的话,当然也不能拿到写锁
        if (w == 0 || current != getExclusiveOwnerThread())
            return false;
        // 到这里,说明当前线程持有锁
        // 重入写锁计数累加不能超过阈值,否则报错
        if (w + exclusiveCount(acquires) > MAX_COUNT)
            throw new Error("Maximum lock count exceeded");
        // Reentrant acquire
        // 设置state的重入计数
        setState(c + acquires);
        return true;
    }
    // 如果state等于0,说明现在还没有人持有任何锁
    // 看是否按照公平原则来依次获取写锁,如果不是最早的waiter,那么会return
    // 如果非公平模式,那么会尝试设置写锁计数,成功的话,绑定当前线程
    // 否则返回
    if (writerShouldBlock() ||
        !compareAndSetState(c, c + acquires))
        return false;
    setExclusiveOwnerThread(current);
    return true;
}

tryRelease

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

tryWriteLock

final boolean tryWriteLock() {
    Thread current = Thread.currentThread();
    int c = getState();
    if (c != 0) {
        int w = exclusiveCount(c);
        // c不等0,w等于0,说明现在有人持有读锁,所以写锁拿不到
        // 就算有人持有写锁,如果是别人的话,当然也不能拿到写锁        
        if (w == 0 || current != getExclusiveOwnerThread())
            return false;
        // 是否写锁已经满了
        if (w == MAX_COUNT)
            throw new Error("Maximum lock count exceeded");
    }
    // 尝试独占锁数量加一,成功的线程才能独占并绑定
    if (!compareAndSetState(c, c + 1))
        return false;
    // 设置当前持有人
    setExclusiveOwnerThread(current);
    return true;
}

ReadLock

tryReadLock

final boolean tryReadLock() {
    Thread current = Thread.currentThread();
    // 自旋
    for (;;) {
        int c = getState();
        // 如果有人持有写锁,且不是自己,那么读锁获取失败,返回false
        if (exclusiveCount(c) != 0 &&
            getExclusiveOwnerThread() != current)
            return false;
        // 拿到读锁计数,且不能超过阈值
        int r = sharedCount(c);        
        if (r == MAX_COUNT)
            throw new Error("Maximum lock count exceeded");
        // 因为读锁可以多个竞争者持有,那么这里尝试去累加读锁计数,成功,说明拿到读锁
        if (compareAndSetState(c, c + SHARED_UNIT)) {
            // 如果之前的计数为0,那么这个线程应该是第一个持有人,设置firstreader和HoldCount
            if (r == 0) {
                firstReader = current;
                firstReaderHoldCount = 1;
            // 直接firstReaderHoldCount累加
            } else if (firstReader == current) {
                firstReaderHoldCount++;
            } else {
                // cachedHoldCounter可以理解为最近一次读锁的持有人及计数
                HoldCounter rh = cachedHoldCounter;
                // 如果rh为空或持有人不是当前线程,那么去获取当前线程的HoldCounter
                if (rh == null || rh.tid != getThreadId(current))
                    // 如果当前线程没有的话,会去init一个
                    // 或拿到持有人的HoldCounter
                    cachedHoldCounter = rh = readHolds.get();
                else if (rh.count == 0)
                    readHolds.set(rh);
                // 计数累加
                rh.count++;
            }
            // 成功拿到读锁,结束自旋
            return true;
        }
    }
}

tryAcquireShared

protected final int tryAcquireShared(int unused) {
    Thread current = Thread.currentThread();
    int c = getState();
    // 如果当前状态时被其他线程独占,返回-1
    if (exclusiveCount(c) != 0 &&
        getExclusiveOwnerThread() != current)
        return -1;
    // 拿到当前共享锁的数量
    int r = sharedCount(c);
    // readerShouldBlock返回false
    // 1. 下一个等待的线程必须是自己 (公平锁)
    // 2. 只要下一个等待的不是写锁,谁来都可以 (非公平锁)
    // 总之是可以拿读锁的状态
    if (!readerShouldBlock() &&
        r < MAX_COUNT &&
        // CAS只要修改成功,就拿到锁
        compareAndSetState(c, c + SHARED_UNIT)) {
        // 如果当前还没有人共享,设置firstReader以及firstReaderHoldCount
        if (r == 0) {
            firstReader = current;
            firstReaderHoldCount = 1;
        // 如果firstReader已经是当前线程,只需要累加firstReaderHoldCount,记录重入数
        } else if (firstReader == current) {
            firstReaderHoldCount++;
        } else {
            HoldCounter rh = cachedHoldCounter;
            // 如果rh为空或持有人不是当前线程,那么去获取当前线程的HoldCounter
            if (rh == null || rh.tid != getThreadId(current))
                // 如果当前线程没有的话,会去init一个
                // 或拿到持有人的HoldCounter
                cachedHoldCounter = rh = readHolds.get();
            else if (rh.count == 0)
                readHolds.set(rh);
            // 自增当前线程的共享锁数目
            rh.count++;
        }
        // 成功拿到锁,返回
        return 1;
    }
    // 如果上面的步骤还没有拿到锁,那么进入自旋模式
    return fullTryAcquireShared(current);
}
final int fullTryAcquireShared(Thread current) {
    /*
     * This code is in part redundant with that in
     * tryAcquireShared but is simpler overall by not
     * complicating tryAcquireShared with interactions between
     * retries and lazily reading hold counts.
     */
    HoldCounter rh = null;
    // 自旋
    for (;;) {
        int c = getState();
        // 如果当前有其他人持有写锁,那么返回-1,进入等待队列
        // 那么有种情况是,正好是当前线程持有写锁,那么直接去下面执行锁降级
        if (exclusiveCount(c) != 0) {
            if (getExclusiveOwnerThread() != current)
                return -1;
            // else we hold the exclusive lock; blocking here
            // would cause deadlock.
        // 进到这里,说明当前没有人持有写锁,但是因为下面的原因导致获取读锁应该等待
        // 1. 下个等待的线程不是自己 (公平锁)
        // 2. 下一个等待的线程需要的写锁,非公平模式下写锁优先 (非公平锁)
        } else if (readerShouldBlock()) {
            // Make sure we're not acquiring read lock reentrantly
            // 应该是个优化,如果发现读锁列表中跟firstReader匹配
            // 说明是个重入读锁,直接去下面去累加重入计数
            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");
        // CAS获取读锁,并做记录
        if (compareAndSetState(c, c + SHARED_UNIT)) {
            // 如果读锁为0,那么记录下firstReader和HoldCount
            if (sharedCount(c) == 0) {
                firstReader = current;
                firstReaderHoldCount = 1;
            // 如果firstReader已经是当前线程,只需要累加firstReaderHoldCount,记录重入数
            } else if (firstReader == current) {
                firstReaderHoldCount++;
            } else {
                // 设置当前线程为cachedHoldCounter
                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;
        }
    }
}

tryReleaseShared

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

FairSync

writerShouldBlock&readerShouldBlock

public final boolean hasQueuedPredecessors() {
    // The correctness of this depends on head being initialized
    // before tail and on head.next being accurate if the current
    // thread is first in queue.
    Node t = tail; // Read fields in reverse initialization order
    Node h = head;
    Node s;
    // true. 
    //    没有等待线程
    //    有,但不是当前线程
    // false
    //    有,且是当前线程
    // 而公平原则下,不像非公平那样写锁优先的逻辑,只是看队列的顺序,轮到谁了,谁来拿锁。
    return h != t &&
        ((s = h.next) == null || s.thread != Thread.currentThread());
}

NonfairSync

writerShouldBlock

final boolean writerShouldBlock() {
    // 非公平下写锁是可以插队的,只要你够幸运
    return false; // writers can always barge
}

readerShouldBlock

final boolean apparentlyFirstQueuedIsExclusive() {
    Node h, s;
    // true
    //    有等待列表,且最早的等待的线程不是为了读锁,且thread不为空
    //    换句话说,读锁是否需要等待得看后面等待的是不是写锁,如果是,写锁优先。
    return (h = head) != null &&
        (s = h.next)  != null &&
        !s.isShared()         &&
        s.thread != null;
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,546评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,224评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,911评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,737评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,753评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,598评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,338评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,249评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,696评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,888评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,013评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,731评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,348评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,929评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,048评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,203评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,960评论 2 355

推荐阅读更多精彩内容