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组件总结的主要内容,如果未能解决你的问题,请参考以下文章