浅析可重入锁的加锁释放锁过程

一、AQS

AQSAbstractQueuedSynchronizer,抽象队列同步器,是juc的基础,如常用的ReentrantLockSemaphoreCountDownLatchReentrantReadWriteLock等都是基于AQS来进行设计的。

AQS通过维护一个同步状态state和一个双向队列CLH来实现加锁释放锁。

CLH队列中存放的Node结点主要关注如下几个属性:

  • waitStatus:等待状态,取值分别为CANCELLED = 1SIGNAL = -1CONDITION = -2PROPAGATE = -3,以及初始时的0
  • prev:当前结点的前驱结点
  • next:当前结点的后继结点
  • thread:当前结点对应的线程

二、加锁

lock默认为非公平锁

1、调用lock.lock()进行加锁,lock()方法内部调用sync.lock()方法进行加锁,非公平锁中,syncNonfairSync的实例,其具体加锁代码如下

final void lock() {
   
   
    // 自旋,设置AQS中同步状态 state 的值,如果 state 为0,表示当前没有线程持有锁,则将其设置为1
    if (compareAndSetState(0, 1))
        // 设置当前线程持有排他锁,加锁结束
        setExclusiveOwnerThread(Thread.currentThread());
    else
        // 如果自旋失败,则表示已经有线程持有锁,state 的值不为0(大于0)
        // 则通过排他模式获取锁,如果获取不成功,则进入队列
        acquire(1);
}

2、acquire方法,代码如下

public final void acquire(int arg) {
   
   
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

2.1、该方法的重点在于if判断,首先是 tryAcquire,在子类NonfairSync中实际调用的是nonfairTryAcquire

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

final boolean nonfairTryAcquire(int acquires) {
   
   
    final Thread current = Thread.currentThread();
    // 获取同步状态
    int c = getState();
    // 若同步状态为0,表示当前锁处于空闲状态
    if (c == 0) {
   
   
        // 尝试抢占,这里有并发的可能,所以有可能会抢不到
        if (compareAndSetState(0, acquires)) {
   
   
            // 如果抢到了,那就设置持有者为当前线程,并返回true
            setExclusiveOwnerThread(current);
            return true;
  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值