AQS组件总结

Posted lgxblog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AQS组件总结相关的知识,希望对你有一定的参考价值。

ReentrantLock

ReentrantLock是AQS中独占模式的一种实现。内部定义了一个继承了AQS类的Syn类。该类有两个子类。而Syn类定义模板方法lock()方法给子类去实现。其中一个子类是实现公平锁,另一个是实现非公平锁。

非公平锁的实现

非公平锁的实现很简单,通过CAS操作判断state这个变量是不是为0,如果是0,则将state设置为1,并且将持有锁的线程改为当前拿到锁的线程。如果是不是0,则调用aquire()方法去抢占锁。代码如下:

 1      /**
 2      * Performs lock.  Try immediate barge, backing up to normal
 3      * acquire on failure.
 4      */
 5     final void lock() {
 6         if (compareAndSetState(0, 1))
 7             setExclusiveOwnerThread(Thread.currentThread());
 8         else
 9             acquire(1);
10     }

因为acquire()方法需要调用tryAcquire()方法,而AQS定义了一个模板给子类去实现,所以Syn类去实现了这个方法。而Syn的非公平锁的tryAcquire()实际上调用的是Syn的nonfairTryAcquire()方法,代码如下:

 1        protected final boolean tryAcquire(int acquires) {
 2              return nonfairTryAcquire(acquires);
 3         }
 4        final boolean nonfairTryAcquire(int acquires) {
 5             final Thread current = Thread.currentThread();
 6             int c = getState();
 7             if (c == 0) {
 8                 if (compareAndSetState(0, acquires)) {
 9                     setExclusiveOwnerThread(current);
10                     return true;
11                 }
12             }
13             //这里是为什么可重入的原因
14             else if (current == getExclusiveOwnerThread()) {
15             //判断当前线程是不是持有锁的线程,因为该线程在继续获取锁,那么直接将state变量值递增。
16                 int nextc = c + acquires;
17                 if (nextc < 0) // overflow
18                     throw new Error("Maximum lock count exceeded");
19                 setState(nextc);
20                 return true;
21             }
22             //未争抢到返回false
23             return false;
24         }

公平锁

公平锁的实现相比非公平锁的实现,相对来说复杂了一点点,公平锁的加锁方式是直接acquire()方法,因为公平锁不能去抢占。

 1 static final class FairSync extends Sync {
 2         private static final long serialVersionUID = -3000897897090466540L;
 3         //加锁的方法,直接调用acquire()方法继而调用自己实现的tryAcquire()方法
 4         final void lock() {
 5             acquire(1);
 6         }
 7 
 8         /**
 9          * Fair version of tryAcquire.  Don‘t grant access unless
10          * recursive call or no waiters or is first.
11          */
12         protected final boolean tryAcquire(int acquires) {
13             final Thread current = Thread.currentThread();
14             int c = getState();
15             if (c == 0) {
16                 //这里需要判断当前线程是不是在同步队列的队首
17                 if (!hasQueuedPredecessors() &&
18                     compareAndSetState(0, acquires)) {
19                     setExclusiveOwnerThread(current);
20                     return true;
21                 }
22             }
23             //这里的逻辑是和公平锁一样的,就是判断是不是当前线程是不是已经是获取到锁的线程,是的话将state变量值递增
24             else if (current == getExclusiveOwnerThread()) {
25                 int nextc = c + acquires;
26                 if (nextc < 0)
27                     throw new Error("Maximum lock count exceeded");
28                 setState(nextc);
29                 return true;
30             }
31             return false;
32         }
33     }

来看看hasQueuedPredecessors()方法

 1 public final boolean hasQueuedPredecessors() {
 2         // The correctness of this depends on head being initialized
 3         // before tail and on head.next being accurate if the current
 4         // thread is first in queue.
 5         Node t = tail; // Read fields in reverse initialization order
 6         Node h = head;
 7         Node s;
 8         return h != t &&
 9             ((s = h.next) == null || s.thread != Thread.currentThread());
10     }

很显然可以看出,就是判断当前线程是不是同步队列的队首节点,以此来判断是不是有比当前线程等待更久的线程。以此来实现公平。

总结

ReentrantLock相对于synchronized的区别:

1) ReentrantLock可以实现公平锁和非公平锁。

2) ReentrantLock可中断

3) ReentrantLock需要手动加锁,释放锁

4) ReentrantLock是JDK API层面的,而synchronized是JVM层面的

以上是关于AQS组件总结的主要内容,如果未能解决你的问题,请参考以下文章

原来 AQS实现原理还能如此总结

AQS总结

AQS总结

AQS 同步组件学习

5-1. AQS(AbstarctQueuedSynchronizer)

VsCode 代码片段-提升研发效率