ReentrantLock-可重入锁

本文详细解析了ReentrantLock的实现原理,包括其属性、构造器、核心方法等,并对比了公平锁和非公平锁的不同之处。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

ReentrantLock 可重入锁:ReentrantLock锁在同一个时间点只能被一个线程锁持有;而可重入的意思是,ReentrantLock锁,可以被单个线程多次获取。

类图

在这里插入图片描述

实现原理

1、属性
private final ReentrantLock.Sync sync;
    /**
     * 非公平锁
     */
    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;
        /**
         * Performs lock.  Try immediate barge, backing up to normal
         * acquire on failure.
         */
        final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }

    /**
     * 公平锁
     */
    static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;

        final void lock() {
            acquire(1);
        }

        /**
         * Fair version of tryAcquire.  Don't grant access unless
         * recursive call or no waiters or is first.
         */
        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;
        }
    }

ReentrantLock的实现有公平锁(FairSync)和非公平锁(NonfairSync)2种。
默认是非公平锁。

公平锁:
在“公平锁”的机制下,线程依次排队获取锁。如果同时2个线程争夺锁资源, 第一个线程获取到了锁,第二个线程就会被加入到队列中进行等待。

非公平锁:
主要是通过CAS算法进行随机匹配,没有队列的概念。但是如果通过CAS计算还是没有获取到锁的话,就会继续进行尝试获取锁。

2、构造器
    public ReentrantLock() {
        this.sync = new ReentrantLock.NonfairSync();
    }

    public ReentrantLock(boolean var1) {
        this.sync = (ReentrantLock.Sync)(var1 ? new ReentrantLock.FairSync() : new ReentrantLock.NonfairSync());
    }

默认是创建一个非公平锁。

3、核心方法
	// 获取锁,给当前线程加锁
    public void lock() {
        this.sync.lock();
    }

	// 如果当前线程未被中断,则获取锁定。如果已经被中断,则抛出异常。
    public void lockInterruptibly() throws InterruptedException {
        this.sync.acquireInterruptibly(1);
    }

	// 尝试去获取锁
    public boolean tryLock() {
        return this.sync.nonfairTryAcquire(1);
    }

	// 尝试在固定的时间去获取锁
    public boolean tryLock(long var1, TimeUnit var3) throws InterruptedException {
        return this.sync.tryAcquireNanos(1, var3.toNanos(var1));
    }

	// 释放锁
    public void unlock() {
        this.sync.release(1);
    }
	
	// 创建对象监视器。
    public Condition newCondition() {
        return this.sync.newCondition();
    }

	// 查询当前线程保持锁定的个数
    public int getHoldCount() {
        return this.sync.getHoldCount();
    }
	
	// 判断当前线程是否保持锁定状态
    public boolean isHeldByCurrentThread() {
        return this.sync.isHeldExclusively();
    }

	// 查询此锁是否由任意线程保持
    public boolean isLocked() {
        return this.sync.isLocked();
    }

	// 判断锁的类型是否是公平锁
    public final boolean isFair() {
        return this.sync instanceof ReentrantLock.FairSync;
    }

	// 查询队列中是否存在等待获取锁的线程数
    public final boolean hasQueuedThreads() {
        return this.sync.hasQueuedThreads();
    }

	// 查询队列中是否存在指定等待获取锁的线程
    public final boolean hasQueuedThread(Thread var1) {
        return this.sync.isQueued(var1);
    }

	// 等待获取此锁的线程的估计数
    public final int getQueueLength() {
        return this.sync.getQueueLength();
    }
	
	// 查询队列中所有的线程数
    protected Collection<Thread> getQueuedThreads() {
        return this.sync.getQueuedThreads();
    }

不同点

非公平锁和公平锁的两处不同

非公平锁在调用 lock 后,首先就会调用 CAS 进行一次抢锁,如果这个时候恰巧锁没有被占用,那么直接就获取到锁返回了。

非公平锁在 CAS 失败后,和公平锁一样都会进入到 tryAcquire 方法,在 tryAcquire 方法中,如果发现锁这个时候被释放了(state == 0),非公平锁会直接 CAS 抢锁,但是公平锁会判断等待队列是否有线程处于等待状态,如果有则不去抢锁,乖乖排到后面。

公平锁和非公平锁就这两点区别,如果这两次 CAS 都不成功,那么后面非公平锁和公平锁是一样的,都要进入到阻塞队列等待唤醒。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值