深入理解acquire和release原理源码及lock独有特性acquireInterruptibly和tryAcquireNanos

本文详细探讨了Lock接口实现类ReentrantLock的acquire和release原理,包括lock()、acquire()、tryAcquire()等方法的源码分析。ReentrantLock使用非公平锁策略,通过AbstractQueuedSynchronizer(AQS)管理同步状态。当获取锁失败时,线程会被添加到同步队列并进行自旋等待,直到获得锁或者被中断。释放锁时,会唤醒同步队列中的下一个有效线程。此外,ReentrantLock还提供了响应中断和超时等待的获取锁方式。
摘要由CSDN通过智能技术生成

Lock是一个接口,通常会用ReentrantLock(可重入锁)来实现这个接口。

独占式获取锁

1.lock()

ReentrantLock lock=new ReentrantLock();
lock.lock();

当获取锁时通常会调用ReentrantLock的lock()方法。而lock()方法在ReentrantLock是一个抽象方法,默认情况下ReentrantLock是一个非公平锁,
lock()方法具体实现在ReentrantLock的静态内部类NonfairSync中,源码如下:

public class ReentrantLock implements Lock, java.io.Serializable {
   
        abstract static class Sync extends AbstractQueuedSynchronizer {
   
        abstract void lock();
        }
        static final class NonfairSync extends Sync {
   
        final void lock() {
   
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }
}        

这里的lock()方法先通过CAS将state的值从0变为1(ReentrantLock用state表示“持有锁的线程已经重复获取该锁的次数”):当state实际值等于预期值0时,表示当前没有线程持有该锁,更新state值为1,将ExclusiveOwnerThread的值为当前线程(Exclusive是独占的意思,ReentrantLock用exclusiveOwnerThread表示“持有锁的线程”),那么该线程获取锁成功。如果CAS失败。说明state实际值并不是0,也就是说已经有线程持有该锁,此时执行acquire(1)再次请求锁。

2.acquire()

调用acquire():会调用ReentrantLock的静态内部AbstractQueuedSynchronizer的acquire方法()。看源码:

public abstract class AbstractQueuedSynchronizer
    extends AbstractOwnableSynchronizer
    implements java.io.Serializable {
   
    /**
     * Acquires in exclusive mode, ignoring interrupts.  Implemented
     * by invoking at least once {@link #tryAcquire},
     * returning on success.  Otherwise the thread is queued, possibly
     * repeatedly blocking and unblocking, invoking {@link
     * #tryAcquire} until success.  This method can be used
     * to implement method {@link Lock#lock}.
     *
     * @param arg the acquire argument.  This value is conveyed to
     *        {@link #tryAcquire} but is otherwise uninterpreted and
     *        can represent anything you like.
     */
    public final void acquire(int arg) {
   
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
}

从注释我们可以了解到acqiure的作用:我理解的是acquire请求独占锁,忽略所有中断,至少执行一次tryAcquire,如果tryAcquire()再次获取锁成功就直接退出,否则线程进入阻塞- - -唤醒2种状态切换中,直到tryAcquire成功。

可以看到if语句是&&,那么先看tryAcquire()方法。
注:以下方法没有特殊表明都在静态内部类AQS中。
3.tryAcquire()

acquire失败后再次用tryAcquire()获取同步状态。

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;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

nonfairTryAcquire()再次获取锁,先判断state是否为0,如果为0即没有线程获取该锁,通过CAS该线程获取到锁。如果state不为0,判断当前线程是否是getExclusiveOwnerThread即持有锁线程,是的话,就将state++,也就是可重入的体现。否则再次获取同步状态失败。
当state=0通过CAS保证同步,即同一个时刻只有一个线程可以获取到锁,但是如果当前线程是持有锁线程并没有保证同步是因

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值