Java并发--重入锁ReentrantLock如何实现重入性

前言

重入锁ReentrantLock,就是支持线程重进入的锁,它表示该锁能够支持一个线程对资源的重复加锁。synchronized关键字隐士的支持锁的可重入性。利用synchronized,执行线程在获取锁之后仍然可以多次获取锁。而ReentrantLock是通过显示去完成锁的可重入性,接下来我们探讨ReentrantLock如何实现可重入性。

正文

重入性是指任意现场在获取到锁之后再次获取该锁而不会被锁阻塞,重入性的实现主要需要解决两个问题。

  • 线程再次获取锁。锁需要去识别获取锁的线程是否为当前占据锁的线程,如果是,则获取锁成功。
  • 锁的最终释放。线程重复n次获取了锁,当第n次释放锁后,其他线程能够获取到锁。

线程获取锁

以非公平性(默认)实现为例,当线程通过ReentrantLock的lock()方法再次获取锁时,会调用nonfairTryAcquire方法获取同步状态,在该方法中判断获取锁的线程是否为当前持有锁的线程。

        final boolean nonfairTryAcquire(int acquires) {
            // 获取当前线程
            final Thread current = Thread.currentThread();
            // 获取同步状态
            int c = getState();
            // 同步状态为0,表示没有线程获取锁
            if (c == 0) {
                // CAS获取同步状态
                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;
        }

同步状态为0不难理解,说明目前没有任何线程获取到锁。而当同步状态不为0时,通过判断当前线程是否为获取锁的线程来决定操作是否成功,如果是获取锁的线程再次请求,则将同步状态的值进行增加并返回true,表示同步状态成功。

注:setExclusiveOwnerThread(current)方式是设置AbstractOwnableSynchronizer的成员变量exclusiveOwnerThread,该变量表明独占式锁的线程所有者。

锁释放

线程通过ReentrantLock的unlock()方法来释放锁,会调用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;
        }

从tryRelease方法中可以看到,同步状态是否为0是锁是否最终被释放的依据,当且仅当同步状态为0,将占有线程设置为null,并返回true,表示释放成功。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值