栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

AQS系列之排斥锁的应用解析:ReentrantLock

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

AQS系列之排斥锁的应用解析:ReentrantLock

AQS系列之AbstractQueuedSynchronizer基础分析
AQS系列之以排斥锁分析
AQS系列之共享锁解析
AQS系列之共享锁的应用解析:Semaphore
AQS系列之共享锁的应用解析:CountDownLatch
AQS系列之排斥锁的应用解析:ReentrantLock


AQS系列之排斥锁的应用解析:ReentrantLock
  • 一、简介
    • 1. Sync
    • 2. state
    • 3. exclusiveOwnerThread
  • 二、获取锁
      • 1. 非公平锁UnFairSync
    • 2. 公平锁FairSync
  • 三、释放锁


一、简介

ReentrantLock即可重入锁,算得上是最常见的一个AQS应用类的,其作用和JAVA关键字synchronized相当。

1. Sync

和Semaphore相似,ReentrantLock也是通过一个抽象类Sync继承了AbstractQueuedSynchronizer,Sync又有两个子类FairSync和UnFairSync,分别代表公平锁和非公平锁。
ReentrantLock有两个构造方法,public ReentrantLock(boolean fair)指定公平策略,public ReentrantLock()无参构造器则默认使用非公平锁。

2. state

state在不同的AQS里有不同的含义,比如Semaphore的permits数量和CountDownLatch的计数值count,在ReentrantLock里可以理解为锁的重入次数。
在ReentrantLock里,state固定初始化为0,代表无锁状态,线程获得锁计数修改为1,后续该线程每次重入都会使计数加1,离开锁时减1,直到state=0重新加入无锁状态,其他线程可以竞争获得锁。

3. exclusiveOwnerThread

exclusiveOwnerThread字段是由AbstractQueuedSynchronizer的父类AbstractOwnableSynchronizer提供的一个字段,可以用于代表当前获取资源的线程。

二、获取锁

获取锁方法为lock,调用AQS固定的acquire(1)方法

public void lock() {
    sync.lock();
}
1. 非公平锁UnFairSync
final void lock() {
	//先快速尝试,失败再进入acquire流程
    if (compareAndSetState(0, 1))
        setExclusiveOwnerThread(Thread.currentThread());
    else
        acquire(1);
}
protected final boolean tryAcquire(int acquires) {
    return nonfairTryAcquire(acquires);
}
inal boolean nonfairTryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    //无锁状态,CAS获取锁
    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;
}

代码里加了简单的注释,逻辑很清晰
(1)获取当前state,根据是否有锁状态分别处理
(2)无锁状态:CAS修改state拿锁,修改成功则说明获取锁成功,否则说明有其他线程竞争到了锁,反悔失败
(3)有锁状态:判断持锁线程是否是当前线程,是则进行重入,state加1,否则返回失败

2. 公平锁FairSync
final void lock() {
    acquire(1);
}
protected final boolean tryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) {
    	//没有前驱节点才能通过CAS拿锁
        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;
}

看过之前对Semaphore解析的文章一眼就能看明白这个逻辑,公平锁的特性就是先到先得,因此和非公平锁的差异就是无锁状态下只有队列里没有当前线程的前驱节点时才能去竞争锁。

三、释放锁

获取锁方法为unLock,调用AQS固定的release(1)方法

public void unlock() {
    sync.release(1);
}
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进入减操作,当state=0了,说明锁完全释放,这时候才返回成功并且将setExclusiveOwnerThread置为null,说明无线程持有锁

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/682260.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号