[JDK源码]J.U.C-AQS-ReentrantLock

AQS原理介绍:

AQS (AbstractQueuedSynchronizer)底层一个队列 阻塞队列 ->
​ Abstract:因为它并不知道怎么上锁。模板方法设计模式即可,暴露出锁逻辑。
​ Queue :线程阻塞队列 Synchronizer:同步
​ CAS + state 完成多线程枪锁逻辑 Queue 完成抢不到锁的线程排队

AQS核心代码

//获取锁
public final void acquire(int arg) {
    if (!tryAcquire(arg) && // 子类判定获取锁是否失败
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) // 获取失败后添加到阻塞队列
        selfInterrupt();
}

// 子类实现获取锁的逻辑,AQS并不知道你怎么用这个state来上锁
protected boolean tryAcquire(int arg) {
    throw new UnsupportedOperationException();
}

//释放锁的
public final boolean release(int arg) {
    // 子类判定释放锁成功
    if (tryRelease(arg)) {
        // 检查阻塞队列唤醒即可
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    return false;
}

// 子类实现获取锁的逻辑
protected boolean tryRelease(int arg) {
    throw new UnsupportedOperationException();
}

子类只需要实现自己的获取锁逻辑和释放锁逻辑即可,至于排队阻塞等待、唤醒机制均由AQS来完成。

公平锁:阻塞队列前边有线程,要去后边排队,简单来说 滚后边等着去。(FIFO) 非公平锁:不管是否有线程排队,先枪锁

ReentrantLock

基于AQS实现的可重入锁实现类。
ReentrantLock 是一个可重入的互斥(/独占)锁,又称为“独占锁”
重入锁: 自己可以再次获取自己的内部的锁。
state 来表示锁状态和重入次数,0无锁,大于0 重入次数,1为重入1次,也即只加锁一次

核心属性

private final Sync sync;//sync,构造方法中初始化,决定使用公平锁还是非公平锁的方式获取锁。

构造方法

	public ReentrantLock() {
        // 默认为非公平锁。
        sync = new NonfairSync();
    }
	public ReentrantLock(boolean fair) {
        // 由fair变量来表明选择锁类型
        sync = fair ? new FairSync() : new NonfairSync();
    }

核心内部类

abstract static class Sync extends AbstractQueuedSynchronizer {}
static final class NonfairSync extends Sync {} 非公平锁
static final class FairSync extends Sync {} 公平锁

            //非公平锁
        static final class NonfairSync extends Sync {
            // 由ReentrantLock调用获取锁
            final void lock() {
                // 非公平锁,直接抢锁,不管有没有线程排队
                if (compareAndSetState(0, 1))
                    // 上锁成功,标识当前线程为获取锁的线程
                    setExclusiveOwnerThread(Thread.currentThread());
                else
                    // 抢锁失败,进入AQS的标准获取锁流程
                    acquire(1);
            }

            protected final boolean tryAcquire(int acquires) {
                // 使用父类提供的获取非公平锁的方法来获取锁
                return nonfairTryAcquire(acquires);
            }
        }
        //公平锁
        static final class FairSync extends Sync {
            // 由ReentrantLock调用
            final void lock() {
                // 没有尝试抢锁,直接进入AQS标准获取锁流程
                acquire(1);
            }

            // AQS调用,子类自己实现获取锁的流程
            protected final boolean tryAcquire(int acquires) {
                final Thread current = Thread.currentThread();
                int c = getState();
                // 此时有可能正好获取锁的线程释放了锁,也有可能本身就没有线程获取锁
                if (c == 0) {
                   //这里和非公平锁的区别在于:hasQueuedPredecessors看看队列中是否有线程正在排队,没有的话再通过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;
                }
                //需要AQS来将当前线程放入阻塞队列,然后进行阻塞操作等待唤醒获取锁
                return false;
            }
        }

        abstract static class Sync extends AbstractQueuedSynchronizer {
            abstract void lock();
            // 非公平锁标准获取锁方法
            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()) {
                    // 利用state 进行次数记录
                    int nextc = c + acquires;
                    // 如果超过了int表示范围,表明符号溢出,所以抛出异常
                    if (nextc < 0)
                        throw new Error("Maximum lock count exceeded");
                    setState(nextc);//state 变量赋值
                    return true;
                }
                //表明需要AQS来将当前线程放入阻塞队列,然后进行阻塞操作等待唤醒获取锁
                return false;
            }

            // 公平锁和非公平锁公用方法,在释放锁的时候,并不区分是否公平
            protected final boolean tryRelease(int releases) {
                int c = getState() - releases;
                // 如果当前线程不是上锁的那个线程
                if (Thread.currentThread() != getExclusiveOwnerThread())
                    throw new IllegalMonitorStateException();
                boolean free = false;
                // 不是重入锁,那么当前线程一定是释放锁了,把当前AQS用于保存当前锁对象的变量ExclusiveOwnerThread设置为null,表明释放锁成功
                if (c == 0) {
                    free = true;
                    setExclusiveOwnerThread(null);
                }
                //此时state全局变量没有改变,也就意味着在setState之前
                //没有别的线程能够获取锁,保证了以上的操作原子性
                setState(c);
                //释放锁成功了,可以去唤醒正在等待锁的线程
                return free;
            }

            protected final boolean isHeldExclusively() {
                return getExclusiveOwnerThread() == Thread.currentThread();
            }

            final ConditionObject newCondition() {
                return new ConditionObject();
            }
        }

核心方法

public void lock() {//获取锁的操作
    // 直接通过sync同步器上锁
    sync.lock();
}
public void unlock() {//释放锁的操作
    sync.release(1);
}
  • 15
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 14
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值