AQS(5):ReentrantLock

ReentrantLock在行为和语义上与synchronized类似,但是更具可扩展性。该锁是可重入的,并且有公平和非公平两种选项。在学习了AQS之后,理解ReentranLock就更容易了。我们知道,AQS已经提供了状态管理,阻塞,队列管理等功能。继承于它的同步工具类只需要实现诸如tryAcquire,tryRelease等基础方法就能实现锁的功能。自然,在ReentrantLock中也包含了Synchronizer对象。

该类中定义了一个静态抽象类Sync作为公平Sync和非公平Sync的基类,定义了公共的tryRelease方法。

protected final boolean tryRelease(int releases) {
        int c = getState() - releases;
        if (Thread.currentThread() != getExclusiveOwnerThread())
            throw new IllegalMonitorStateException();
            boolean free = false;
        if (c == 0) {
            free = true;
            setExclusiveOwnerThread(null);
        }
        setState(c);
        return free;
}

这个方法非常简单,state可以简单理解为如果大于0表示持有锁时重入次数,如果等于0则没有线程持有锁。因此简单的判断release后是否为0并重新设置state就可以了。该类中还定义了一个nonfairTryAcquire方法。

final boolean nonfairTryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState();
        if (c == 0) {
            if (compareAndSetState(0, acquires)) {
                setExclusiveOwnerThread(current);
                return true;
            }
        }
        else if (current == getExclusiveOwnerThread()) {
            int nextc = c + acquires;
            if (nextc < 0) // overflow
                throw new Error("Maximum lock count exceeded");
            setState(nextc);
            return true;
        }
        return false;
}

该方法的思路仍然是通过state确定是否加锁成功。首先如果state=0,即无人持有锁,那么通过CAS更改state,注意,此处由于可能存在竞争,必须使用CAS而非普通的比较设置两段操作。如果当前线程已经持有锁,那么本次是重入,仅记录一下重入状态就可以了。

接下来是设计公平和非公平的Sync具体子类。我们先来看NonfairSync中的lock方法。

final void lock() {
        if (compareAndSetState(0, 1))
            setExclusiveOwnerThread(Thread.currentThread());
        else
            acquire(1);
}

这就体现了非公平性,他会直接通过判断state强行尝试一次,而不是在队列中排队通过acquire来取得锁。我们整体描述一下非公平锁的lock流程。首先,根据state判断能否立即加锁成功,如果不能则调用acquire;在acquire过程中,调用tryAcquire,这个方法中又会判断一次state,如果又失败,就向同步队列添加一个节点.这种情况下只有当该节点前驱是头结点的时候才会尝试用tryAcquire取得锁,否则就被阻塞。可以看到,在这个过程中,非公平锁至少会两次尝试通过CAS更改state来取得锁。

在fairSync中的tryAcquire方法流程就不同了,由于考虑到公平性,不能只根据state就决定是否取得锁。该过程中,如果无人持有锁,那么判断他有没有前驱节点,如果没有,再让自己持有锁,这就是公平性的体现。

protected final boolean tryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState();
        if (c == 0) {
            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;
        }
        return false;
}

该类中的其他方法基本都是对Sync中定义方法的调用,没有其他的新意,对ReentrantLock的解析就到这里了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值