AQS原理

2020-01-02  本文已影响0人  couriravant

分为独占锁和共享锁:

获取独占锁:

image.png
 final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

CAS设置为1,成功则获取锁,否则调用 acquire获取锁

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

tryAcquire 作用也是做CAS获取锁,如果已经是同一线程重入,state+1(释放时会减1),如果ryAcquire成功就结束,如果没有成功,则通过addWaiter将当前线程包装成一个Node节点,通过CAS原子操作,加入队列的尾部.
acquireQueued() 中会判断这个node节点的前一个节点是不是head节点(也就是持有锁的节点),如果是,那就调用tryAcquire再次通过CAS自旋去尝试获取锁,如果获取锁失败后,进入挂起逻辑。

总结:

在独占锁模式下,用 state 值表示锁并且 0 表示无锁状态,0 -> 1 表示从无锁到有锁,仅允许一条线程持有锁,其余的线程会被包装成一个 Node 节点放到队列中进行挂起,队列中的头节点表示当前正在执行的线程,当头节点释放后会唤醒后继节点,从而印证了 AQS 的队列是一个 FIFO 同步队列。

获取共享锁:

共享功能:只要头节点获取锁成功,就在唤醒自身节点对应的线程的同时,继续唤醒AQS队列中的下一个节点的线程,
每个节点在唤醒自身的同时还会唤醒下一个节点对应的线程,以实现共享状态的“向后传播”,从而实现共享功能。

refer:https://www.jianshu.com/p/76949bca657a
http://objcoding.com/2019/05/05/aqs-exclusive-lock/

上一篇 下一篇

猜你喜欢

热点阅读