ReentrantLock源码解析

ReentrantLock源码解析

简介

ReentrantLock是一种基于AQS框架的应用实现,是JDK中的一种线程并发访问的同步手段,它的功能类似于synchronized,是一种互斥锁,可以保证线程安全。
相对于 synchronized, ReentrantLock具备如下特点:

  • 可中断
  • 可以设置超时时间
  • 可以设置为公平锁(默认非公平)
  • 支持多个条件变量
  • 与 synchronized 一样,都支持可重入

ReentrantLock最重要的是三个内部类Sync、NonfairSync和FairSync。

1、Sync

1.1、 nonfairTryAcquire(int acquires)
非公平锁尝试获取锁。逻辑简单,在AQS中已经讲过了。

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;
        // int最高位为正负标记位
        if (nextc < 0) 
            throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }
    return false;
}

1.2、释放锁 tryRelease(int releases)
只有释放锁完成后满足 c == 0 才返回true,因为重入锁获取了几次就要释放几次。

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;
}

1.3、abstract void lock()
抽象方法,用于子类继承,在公平锁和非公平锁种会分别做具体的实现。

2、NonfairSync extends Sync

非公平锁主要重写两个方法 lock()tryAcquire(int acquires)

2.1 lock()

因为是非公平锁,所以获取锁的时候不排队,先尝试获取锁,获取失败则调用AQS的 acquire() 方法。

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

2.2 tryAcquire(int acquires)

在AQS中说过,子类必须自己写具体的获取锁的逻辑即重写 tryAcquire(int acquires) 方法。
而在非公平锁种, tryAcquire(int acquires) 其实是调用的父类 SyncnonfairTryAcquire(acquires) ,同样是先直接尝试获取锁。

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

2.3 NonfairSync 小结

ReentrantLock的非公平锁在调用Lock() 方法时,会先进行两次CAS尝试获取锁,获取失败后才进入同步队列排队。

3、FairSync extends Sync

3.1 lock()

公平锁的lock()直接调用AQS的 acquire(1) 方法,而不是像非公平锁一样先尝试获取锁。

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

3.2 tryAcquire(int acquires)

在公平锁中,tryAcquire(int acquires) 方法和非公平锁的区别是,不再可以直接CAS尝试获取锁,而是通过AQS 的排队校验方法 hasQueuedPredecessors() 来判断是否需要排队,如果不需要才能尝试获取锁,体现其公平性。

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;
}

3.3 FairSync 小结

ReentrantLock的公平锁在调用Lock() 方法时,判断当前线程是否需要排队来决定是否能够尝试获取锁,相比于非公平锁的两次直接CAS,这样做保证了其公平性(其实公平锁也不是完全公平)。

  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值