AQS是什么?看了之后你就会觉得如此简单

 

目录

原理

原理源码解读

首先看加锁tryAcquire的方法

然后是acquireQueued方法

先看addWaiter方法

acquireQueued方法

解锁release源码


AQS(AbstractQueuedSynchronizer)它是java一个同步工具类,在我们很多常见的类中都有用到他,基于他实现,比如ReentrantLock、ReentrantReadWriteLock、FutureTask等。

原理

 底层用了一个整数类型变量去表示同步状态,并通过CAS管理同步状态对象。

流程大概类似与这样

 

 节点是双向链表,便于移除和添加。

 这样看起来是不是直观很多。

原理源码解读

AQS可以实现独占锁和共享锁,我们以独占锁为例去看

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

首先看加锁tryAcquire的方法

    protected boolean tryAcquire(int arg) {
        throw new UnsupportedOperationException();
    }

发现什么也没有,那必然他的子类重写这个方法,我们以ReentrantLock的NonfairSync为例去看一下。

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

        final boolean nonfairTryAcquire(int acquires) {
            //拿到当前线程
            final Thread current = Thread.currentThread();
            //获取state
            int c = getState();
            //如果为0,认为可以用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;
        }

总的来说 就是获取state,成功返回true,失败则false。

然后是acquireQueued方法

先看addWaiter方法

    private Node addWaiter(Node mode) {
        //把当前线程和mode塞入新创建的Node节点
        Node node = new Node(Thread.currentThread(), mode);
        // Try the fast path of enq; backup to full enq on failure
        Node pred = tail;
        if (pred != null) {
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        enq(node);
        return node;
    }

入参为锁模式(共享还是独占),我们发现其中有个变量tail,看一下它的注释,大概意思是队列的尾部,懒初始化,仅通过enq方法去添加新的等待节点

/**
 * Tail of the wait queue, lazily initialized.  Modified only via
 * method enq to add new wait node.
 */
private transient volatile Node tail;

所以它的大致流程就是判断是否为新的队列,如果不是就往后边加,如果是就新建。

acquireQueued方法

    final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

首先看自己的前直节点是不是头节点,是的话,尝试获取资源成功就把自己设为头节点。失败的话就继续阻塞

解锁release源码

    public final boolean release(int arg) {
        //尝试释放锁,子类实现
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                //释放锁锁成功后唤醒最合适的线程
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

有什么建议或意见请及时提出

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值