从读写锁来看抽象队列同步器(释放读锁)

接着上一篇的,在加了锁之后,就到了释放锁的环节

话不多说,直接上源码

从释放锁进入

readLock.unlock();

public void unlock() {
    //还是默认的非公平锁的释放
 	sync.releaseShared(1);
}

释放锁

public final boolean releaseShared(int arg) {
	//1、尝试释放锁 如果释放之后, 锁的数量为0 则会执行第2步
    if (tryReleaseShared(arg)) {
        //2、唤醒其他线程
        doReleaseShared();
        return true;
    }
    return false;
}

1、尝试释放锁

protected final boolean tryReleaseShared(int unused) {
    Thread current = Thread.currentThread();
    //当前线程是第一个获取读锁的线程
    if (firstReader == current) {
        //持有的锁的数量为1  直接将firstReader置空
        if (firstReaderHoldCount == 1)
            firstReader = null;
        else
            //将持有的锁的数量-1
            firstReaderHoldCount--;
    } else {
        //获取缓存的线程持有的锁的计数器
        HoldCounter rh = cachedHoldCounter;
        //不是本线程的计数器
        if (rh == null || rh.tid != getThreadId(current))
            //从threadlocal中获取
            rh = readHolds.get();
        int count = rh.count;
        //持有锁的数量<=1  直接从threadlocal中移除
        if (count <= 1) {
            readHolds.remove();
            if (count <= 0)
                throw unmatchedUnlockException();
        }
        //将持有的锁
        --rh.count;
    }
    for (;;) {
        //获取锁数量
        int c = getState();
        //为什么这么操作呢?  这就和上锁关联起来了  
        //每加一个锁。state的值就增加SHARED_UNIT 所以每释放一次,也需要减SHARED_UNIT
        int nextc = c - SHARED_UNIT;
        if (compareAndSetState(c, nextc))
            //锁释放成功之后,判断锁的数量是否为0  并且返回
            return nextc == 0;
    }
}

2、唤醒其他线程 在分析加锁的时候,2.2 这一块如果下一个结点需要共享锁,则会唤醒这个线程。 同样,在释放掉一个锁之后,也会尝试唤醒下一个结点线程 源码如下

private void doReleaseShared() {
    for (;;) {
        Node h = head;
        //判断队列不为空
        if (h != null && h != tail) {
            //获取头节点的状态
            int ws = h.waitStatus;
            //等待被唤醒的状态
            if (ws == Node.SIGNAL) {
                //将其状态改为0标识本结点不在作用于同步队列  如果失败,进行下一次循环
                if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
                    continue;            // loop to recheck cases
                //如果成功,唤醒下一个结点  这一步在上一篇加锁已经分析
                unparkSuccessor(h);
            }
            //0状态的话  尝试将其修改为-3  失败的话进入下一次循环
            else if (ws == 0 && !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
                continue;                // loop on failed CAS
        }
        //这一块为什么这么做??没搞懂哦
        if (h == head)                   // loop if head changed
            break;
    }
}

由上可知,在唤醒线程之后,线程会接着上一步继续往下执行,
也就是线程会接着parkAndCheckInterrupt()这个之后去往下走,
因为parkAndCheckInterrupt()让线程暂时堵塞,唤醒之后,就会接着往下走,
然后在一次去获取他的前置结点,并且尝试获取锁,也就是doAcquireShared()里面的自旋

到此位置,释放锁就已经结束了 下一篇分析公平模式下的写锁的加锁与释放

友情参考 https://www.cnblogs.com/waterystone/p/4920797.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值