ReentrantLock源码解析

本文详细解析了ReentrantLock的工作原理,包括其如何利用AQS实现线程的独占锁获取与释放,以及公平锁与非公平锁的区别。ReentrantLock通过内部类Sync实现了与synchronized相似的互斥性和内存可见性,同时提供了更丰富的加锁机制。

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

一、简介

    使用了AQS的独占获取和释放,用state变量记录某个线程获取独占锁的次数,获取锁时+1,释放锁时-1,在获取时会校验线程是否可以获取锁。ReentrantLock类实现了Lock接口,并提供了与synchronized相同的互斥性和内存可见性,它的底层是通过AQS 来实现多线程同步的。与内置锁相比ReentrantLock不仅提供了更丰富的加锁机制,而且在性能上也不逊色于内 置锁(在以前的版本中甚至优于内置锁)。

二、源码解析

    ReentrantLock的内部类Sync继承了AQS,分为公平锁FairSync和非公平锁NonfairSync。如果在绝对时间上,先对锁进行获取的请求你一定先被满足,那么这个锁是公平的,反之,是不公平的。公平锁的获取,也就是等待时间最长的线程最优先获取锁,也可以说锁获取是顺序的。

内部类Sync

//这个锁的同步控制基础。继承自AbstractQueuedSynchronizer类
//子类化为公平和非公平的版本下面。使用AQS状态表示锁上的持有数。
abstract static class Sync extends AbstractQueuedSynchronizer {
    //序列化序号,用来对对象进行反序列化时的判断
    private static final long serialVersionUID = -5179523762034025860L;

    //执行获取锁。子类化的主要原因是允许非公平版本的快速路径。
    abstract void lock();

    //非公平的尝试锁的获取,acquires的值一般为1
    final boolean nonfairTryAcquire(int acquires) {
        //获取当前线程
        final Thread current = Thread.currentThread();
        //获取当前锁的状态,若为0则表示当前没有线程获取锁
        //也可以理解为若不为0,则表示有线程获取锁,而state的值表示获取锁的线程的重入次数
        int c = getState();
        //0表示当前没有线程获取锁
        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");
            // 累加state的值,此段代码实现了重入锁
            setState(nextc);
            return true;
        }
        return false;
    }

    //尝试释放锁,releases的值一般为1
    protected final boolean tryRelease(int releases) {
        //getState()为获取锁的线程的重入次数,若有线程获取锁,则getState的值至少为1
        int c = getState() - releases;
        //如果当前线程与获取锁的线程不等,则抛出异常
        if (Thread.currentThread() != getExclusiveOwnerThread())
            throw new IllegalMonitorStateException();
        boolean free = false;
        //如果得到getState的值并且减去releases后等于0,则释放锁
        //将锁的持有线程变为null
        if (c == 0) {
            free = true;
            setExclusiveOwnerThread(null);
        }
        //重新设置锁的线程的重入次数,一般这个时候为0
        setState(c);
        return free;
    }

    //当前线程是否获取独占锁
    protected final boolean isHeldExclusively() {
        //直接利用getExclusiveOwnerThread方法获取持有锁的线程然后和当前线程进行比较
        return getExclusiveOwnerThread() == Thread.currentThread();
    }

    //返回一个条件队列
    final ConditionObject newCondition() {
        return new ConditionObject();
    }

    //返回当前持有锁的线程
    final Thread getOwner() {
        return getState() == 0 ? null : getExclusiveOwnerThread();
    }

    //返回当前线程的对锁的重入次数
    final int getHoldCount() {
        //先判断当前线程是否获取了锁
        //如果获取了锁则返回对锁的重入次数,如果没有获取锁则返回0
        return isHeldExclusively() ? getState() : 0;
    }

    //判断是否有锁
    final boolean isLocked() {
        return getState() != 0;
    }

    /**
     * Reconstitutes the instance from a stream (that is, deserializes it).
     */
    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        s.defaultReadObject();
        setState(0); // reset to unlocked state
    }
}

同步对象的非公平锁实现

//同步对象的非公平锁
static final class NonfairSync extends Sync {
    private static final long serialVersionUID = 7316153563782823691L;

    //非公平锁的实现
    final void lock() {
        //先用CAS获取锁,即将0变为1,若能够获取成功,则将当前锁的持有者变为当前线程
        if (compareAndSetState(0, 1))
            setExclusiveOwnerThread(Thread.currentThread());
        else
            //若CAS失败,则表示已经有其他线程持有锁
            //然后就利用AQS的获取独占锁的方法来对锁进行获取
            acquire(1);
    }

    //尝试获取独占锁
    protected final boolean tryAcquire(int acquires) {
        //利用Sync内部类的nonfairTryAcquire方法实现锁的获取
        return nonfairTryAcquire(acquires);
    }
}

同步对象的公平锁实现

//同步对象的公平锁
static final class FairSync extends Sync {
    private static final long serialVersionUID = -3000897897090466540L;

    //公平锁的获取,利用AQS的同步队列进行锁的获取
    final void lock() {
        acquire(1);
    }

    //公平锁,尝试对独占锁获取,重写AQS的tryAcquire方法
    protected final boolean tryAcquire(int acquires) {
        //获取当前线程
        final Thread current = Thread.currentThread();
        //获取锁的重入次数
        int c = getState();
        //若为0代表当前锁没有线程持有
        if (c == 0) {
            //hasQueuedPredecessors作用是判断同步队列中是否有其他节点,即是否有线程在排队
            if (!hasQueuedPredecessors() &&
                //若没有线程在排队,则直接利用CAS方法将state状态变为acquires(一般为1)
                compareAndSetState(0, acquires)) {
                //然后设置当前锁的持有线程为当前线程
                setExclusiveOwnerThread(current);
                return true;
            }
        }
        //若当前锁已经被其他线程持有了,则判断当前线程是否为锁的持有线程
        else if (current == getExclusiveOwnerThread()) {
            //若当前线程是锁持有的线程,则重入次数加上acquires(一般为1)
            int nextc = c + acquires;
            if (nextc < 0)
                throw new Error("Maximum lock count exceeded");
            //设置当前锁的重入次数
            setState(nextc);
            return true;
        }
        return false;
    }
}

ReentrantLock的构造方法

ReentrantLock默认是实现了非公平锁的构造方法。

//ReentrantLock默认是非公平的锁的实现
public ReentrantLock() {
    sync = new NonfairSync();
}

//根据参数fair来决定ReentrantLock是公平锁还是非公平锁
public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

ReentrantLock的常用方法

//会根据ReentrantLock是公平锁还是非公平锁来进行不同的锁的获取
public void lock() {
    sync.lock();
}

//可响应中断的获取锁
public void lockInterruptibly() throws InterruptedException {
    //获取独占锁并且可中断当前线程
    sync.acquireInterruptibly(1);
}

//非公平的获取锁
public boolean tryLock() {
    return sync.nonfairTryAcquire(1);
}

//有响应时间的获取锁
//利用AQS的tryAcquireNanos方法,其作用为在指定时间内尝试获取独占锁
public boolean tryLock(long timeout, TimeUnit unit)throws InterruptedException {
    return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}

//释放锁
public void unlock() {
    sync.release(1);
}

//获取条件队列
public Condition newCondition() {
   return sync.newCondition();
}

//返回当前线程的对锁的重入次数
public int getHoldCount() {
    return sync.getHoldCount();
}

//判断获取锁的是不是当前线程
public boolean isHeldByCurrentThread() {
    return sync.isHeldExclusively();
}

//判断锁是否被其他线程持有
public boolean isLocked() {
    return sync.isLocked();
}

//判断ReentrantLock的是基于公平锁还是非公平锁实现
public final boolean isFair() {
    return sync instanceof FairSync;
}

//获取当前持有锁的线程
protected Thread getOwner() {
    return sync.getOwner();
}

//是否有线程在同步队列中,即判断同步队列中是否有元素
public final boolean hasQueuedThreads() {
    return sync.hasQueuedThreads();
}

//判断线程thread是否在同步队列中
public final boolean hasQueuedThread(Thread thread) {
    return sync.isQueued(thread);
}

//获取同步队列的长度,即有多少线程在同步队列中等待
public final int getQueueLength() {
    return sync.getQueueLength();
}

//获取同步队列中的所有线程
protected Collection<Thread> getQueuedThreads() {
    return sync.getQueuedThreads();
}

三、总结

    总的来说,ReentrantLock主要还是利用他的内部类Sync来实现具体操作,他的内部类Sync因为继承自AQS,所以底层大部分的操作还是利用AQS来实现的。而Sync以及他的子类NonfairSync和FairSync只需要实现AQS没有实现的方法即可,例如tryAcquire等方法,然后具体操作还是通过AQS来实现,然后AQS再调用其子类实现的tryAcquire等方法即可完成一系列操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值