多线程高并发编程(3) -- ReentrantLock源码分析AQS
背景:
AbstractQueuedSynchronizer(AQS)
public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable
-
介绍
- 提供一个框架,用于实现依赖先进先出(FIFO)等待队列的阻塞锁和相关同步器(信号量,事件等)。 该类被设计为大多数类型的同步器的有用依据,这些同步器依赖于单个原子
int
值来表示状态。 子类必须定义改变此状态的受保护方法,以及根据该对象被获取或释放来定义该状态的含义。 给定这些,这个类中的其他方法执行所有排队和阻塞机制。 子类可以保持其他状态字段,但只以原子方式更新int
使用方法操纵值getState
()
,setState(int)
和compareAndSetState(int, int)
被跟踪相对于同步。 - 子类应定义为非公共内部助手类,用于实现其封闭类的同步属性。
AbstractQueuedSynchronizer
类不实现任何同步接口。 相反,它定义了一些方法,如acquireInterruptibly(int)
,可以通过具体的锁和相关同步器来调用适当履行其公共方法。 - 此类支持默认独占模式和共享模式。【使用模板模式来定义是独占还是共享模式】 当以独占模式获取时,尝试通过其他线程获取不能成功。 多线程获取的共享模式可能(但不需要)成功。 除了在机械意义上,这个类不理解这些差异,当共享模式获取成功时,下一个等待线程(如果存在)也必须确定它是否也可以获取。 在不同模式下等待的线程共享相同的FIFO队列。 通常,实现子类只支持这些模式之一,但是两者都可以在
ReadWriteLock
中发挥作用 。 仅支持独占或仅共享模式的子类不需要定义支持未使用模式的方法。 - 这个类定义的嵌套
AbstractQueuedSynchronizer
.
ConditionObject
可用于作为一类Condition
由子类支持独占模式用于该方法的实施isHeldExclusively()
份报告是否同步排他相对于保持在当前线程,方法release(int)
与当前调用getState()
值完全释放此目的,和acquire(int)
,给定此保存的状态值,最终将此对象恢复到其先前获取的状态。AbstractQueuedSynchronizer
方法将创建此类条件,因此如果不能满足此约束,请勿使用该约束。AbstractQueuedSynchronizer.ConditionObject
的行为当然取决于其同步器实现的语义。 - 该类为内部队列提供检查,检测和监控方法,以及条件对象的类似方法。 这些可以根据需要导出到类中,使用
AbstractQueuedSynchronizer
进行同步机制。 - 此类的序列化仅存储底层原子整数维持状态,因此反序列化对象具有空线程队列。 需要可序列化的典型子类将定义一个
readObject
方法,可以将其恢复为readObject
时的已知初始状态。
-
用法
使用这个类用作同步的基础上,重新定义以下方法,【即在同步器中定义内部类重写下面的方法】,如适用,通过检查和/或修改使用所述同步状态
getState()
,setState(int)
或compareAndSetState(int,
int)【通过这三个方法来保证原子性和线程安全性】
:tryAcquire(int)独占模式获取锁
tryRelease(int)独占模式释放锁
tryAcquireShared(int)共享模式获取锁
tryReleaseShared(int)共享模式释放锁
isHeldExclusively()是否是独占式
UnsupportedOperationException
。 这些方法的实现必须是线程安全的,通常应该是短的而不是阻止的。 定义这些方法是唯一支持使用此类的方法。 所有其他方法都被声明为final
,因为它们不能独立变化。 -
看下面的源码分析前可先观看多线程高并发编程(2) -- 可重入锁介绍和自定义
一.ReentrantLock的lock和unlock源码解析
- 使用流程分析:A、B两个线程同时执行lock()方法获取锁,假设A先执行获取到锁,此时state值加1,如果线程A在继续执行的过程中又执行了lock()方法,线程A会直接获取锁,同时state值加1,state的值可以简单理解为线程A执行lock()方法的次数;当线程B执行lock()方法获取锁时,会将线程B封装成Node节点,并将其插入到同步等待队列的尾部,然后阻塞当前线程,等待被唤醒再次尝试获取锁;线程A每次执行unlock()方法都会将state值减1,直到state的值等于零则表示完全释放掉了线程A持有的锁,此时将从同步等待队列的头节点开始唤醒阻塞的线程,阻塞线程恢复执行,再次尝试获取锁。ReentrantLock公平锁的实现使用了AQS的同步等待队列和state。
-
lock流程:
- 调用同步器Sync的抽象方法lock,由公平锁FairSync实现
- 调用AQS的acquire获取锁
- 尝试获取锁:公平锁FairSync的tryAcquire
- 第一次获取锁,若队列没有前节点和设置状态成功,存储当前线程,返回true,表示获取成功;
- 如果是重入获取,锁持有数量+1;
- 获取锁失败,把当前线程加入等待队列中,并对等待队列进行阻塞,不断竞争获取锁:acquireQueued遍历等待队列addWaiter,若有头节点则从队列中取出来,若没有则进行中断;
- 尝试获取锁:公平锁FairSync的tryAcquire
-
unlock流程:
- 调用同步器的release方法,有AQS实现;
- tryRelease释放锁,由Sync实现
- 锁数量-1;
- 当前线程和保存的线程不一致抛出异常;
- 锁数量为0则进行释放锁,把独占线程设置为null,修改状态;
1 //===========================ReentrantLock源码=============================== 2 public class ReentrantLock implements Lock, java.io.Serializable { 3 private final Sync sync;//同步器 4 public void lock() {//获取锁 5 sync.lock();//调用同步器Sync的lock,由FairSync实现 6 } 7 public void unlock() {//使用锁 8 sync.release(1);//调用同步器的release,由AQS实现 9 } 10 11 12 //内部类,同步器继承AQS,实现tryRelease释放锁 13 abstract static class Sync extends AbstractQueuedSynchronizer{ 14 abstract void lock();//获取锁抽象方法,由FairSync实现 15 //===========================释放锁=============================== 16 protected final boolean tryRelease(int releases) { 17 int c = getState() - releases;//锁数量-1 18 //当前线程和保存的线程不一致 19 if (Thread.currentThread() != getExclusiveOwnerThread()) 20 throw new IllegalMonitorStateException(); 21 boolean free = false; 22 if (c == 0) {//持有的锁数量为0 23 free = true;//释放锁 24 setExclusiveOwnerThread(null);//当前独占线程为null 25 } 26 setState(c);//设置状态 27 return free; 28 } 29 } 30 31 //内部类,公平锁继承同步器,实现lock方法 32 static final class FairSync extends Sync { 33 //===========================获取锁=============================== 34 final void lock() { 35 acquire(1);//调用AQS的acquire 36 } 37 protected final boolean tryAcquire(int acquires) { 38 final Thread current = Thread.currentThread();//获得当前线程 39 /**getState是AQS的Node的waitStatus,其值有 40 *CANCELLED = 1 41 *SIGNAL = -1 42 *CONDITION = -2 43 *PROPAGATE = -3 44 */ 45 int c = getState(); 46 //c初始值为0,0表示不是以上的状态;hasQueuedPredecessors之前是否有节点, 47 //如果是true表示这个线程的前面还有节点应该让前面的节点先获取锁,当前线程获取失败; 48 //【非公平锁少了hasQueuedPredecessors这个判断】 49 //compareAndSetState CAS比较,设置当前状态为1;setExclusiveOwnerThread当前线程设置为独占线程 50 if (c == 0) { 51 if (!hasQueuedPredecessors() && 52 compareAndSetState(0, acquires)) { 53 setExclusiveOwnerThread(current); 54 return true;//获取成功 55 } 56 } 57 else if (current == getExclusiveOwnerThread()) {//如果是当前线程,表示重入 58 int nextc = c + acquires;//锁数量+1 59 if (nextc < 0)//小于0表示溢出 60 throw new Error("Maximum lock count exceeded"); 61 setState(nextc);//更新状态 62 return true;//获取成功 63 } 64 return false;//获取失败 65 } 66 } 67 } 68 69 70 71 //=============AbstractQueuedSynchronizer源码============== 72 public abstract class AbstractQueuedSynchronizer 73 extends AbstractOwnableSynchronizer 74 implements java.io.Serializable{ 75 //===========================获取锁=============================== 76 //以独占模式获取,忽略中断。通过调用至少一次tryAcquire(int)实现,成功返回。否则线程排队, 77 //可能会重复阻塞和解除阻塞,直到成功才调用tryAcquire(int)。 78 public final void acquire(int arg) {//FairSync的lock调用 79 //tryAcquire获取锁;acquireQueued线程加入到了等待队列中,进行阻塞等待,竞争获取锁; 80 //addWaiter其他线程获取锁失败添加到等待队列中;Node.EXCLUSIVE节点独占,为null 81 if (!tryAcquire(arg) && 82 acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) 83 selfInterrupt(); 84 } 85 protected boolean tryAcquire(int arg) {//acquire调用,由FairSync实现 86 throw new UnsupportedOperationException(); 87 } 88 final boolean acquireQueued(final Node node, int arg) {//acquire调用 89 boolean failed = true; 90 try { 91 boolean interrupted = false; 92 for (;;) { 93 final Node p = node.predecessor();//获取前一个节点 94 if (p == head && tryAcquire(arg)) {//如果获取的节点为头节点并且获取到锁 95 setHead(node);//当前节点设置为头节点 96 p.next = null;//头节点下一节点为空,即把当前节点从队列中移除出来 97 failed = false; 98 return interrupted; 99 } 100 //当前节点不是头节点,parkAndCheckInterrupt让当前线程处于阻塞等待状态由其他线程唤醒 101 if (shouldParkAfterFailedAcquire(p, node) && 102 parkAndCheckInterrupt()) 103 interrupted = true; 104 } 105 } finally { 106 if (failed) 107 cancelAcquire(node); 108 } 109 } 110 private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {//acquireQueued调用 111 int ws = pred.waitStatus;//获取前一节点的等待状态 112 if (ws == Node.SIGNAL)//如果状态为唤醒状态 113 return true; 114 if (ws > 0) {//处于CANCELLED状态 115 do { 116 node.prev = pred = pred.prev;//1.把所有处于CANCELLED状态的节点移除 117 } while (pred.waitStatus > 0); 118 pred.next = node;//2.把所有处于CANCELLED状态的节点移除 119 } else { 120 compareAndSetWaitStatus(pred, ws, Node.SIGNAL);//设置为SIGNAL状态 121 } 122 return false; 123 } 124 private Node addWaiter(Node mode) {//acquireQueued的参数,在acquire中调用 125 Node node = new Node(Thread.currentThread(), mode);//创建Node,当前线程指向node 126 Node pred = tail;//前节点指向尾节点【双向链表】 127 if (pred != null) {//尾节点不为空 128 node.prev = pred;//当前线程节点指向尾节点 129 if (compareAndSetTail(pred, node)) {//CAS比较,把当前线程节点更新为尾节点 130 pred.next = node;//前尾节点的下一节点指向当前尾节点 131 return node; 132 } 133 } 134 enq(node);//如果尾节点为空,把当前节点放到一个初始化节点或添加到节点中做为尾节点 135 return node; 136 } 137 private Node enq(final Node node) {//addWaiter调用 138 for (;;) { 139 Node t = tail; 140 if (t == null) { // 尾节点为空 141 if (compareAndSetHead(new Node()))//创建新节点并维护一个头节点 142 tail = head;//把当前节点设置为头节点 143 } else { 144 node.prev = t;//当前节点指向尾节点 145 if (compareAndSetTail(t, node)) {//把当前节点更新为尾节点 146 t.next = node;//前尾节点的下一节点指向当前尾节点 147 return t; 148 } 149 } 150 } 151 } 152 static void selfInterrupt() {//acquire调用 153 Thread.currentThread().interrupt();//当前线程中断 154 } 155 //===========================释放锁=============================== 156 public final boolean release(int arg) {//ReentrantLock的unlock调用 157 if (tryRelease(arg)) {//当前线程锁释放成功,唤醒其他线程进行资源的竞争 158 Node h = head; 159 if (h != null && h.waitStatus != 0) 160 unparkSuccessor(h); 161 return true; 162 } 163 return false; 164 } 165 protected boolean tryRelease(int arg) {//release调用,由Sync实现 166 throw new UnsupportedOperationException(); 167 } 168 }
备注:公平锁是针对锁的获取而言,如果一个锁是公平的,那么锁的获取顺序就应该符合请求的绝对时间顺序;非公平锁会进行插队获取锁;
二.AQS重写锁
流程:
- 实现Lock,重写实现方法lock、lockInterruptibly、tryLock、unlock、newCondition;
- 内部类继承AQS,重写tryAcquire和tryRelease;
1 public class MyAQSLock implements Lock{ 2 private MyAQS myAQS; 3 private class MyAQS extends AbstractQueuedSynchronizer{ 4 @Override 5 protected boolean tryAcquire(int arg) { 6 int state = getState();//获取状态 7 Thread thread = Thread.currentThread(); 8 if(state==0){//线程第一次进来获取,状态为0,表示可以拿到锁 9 if(compareAndSetState(0,arg)){//更新状态 10 setExclusiveOwnerThread(Thread.currentThread());//设置为独占线程,其他线程进来进入等待 11 return true;//获取成功 12 } 13 }else if(getExclusiveOwnerThread()== thread){//重入,存储线程等于当前线程 14 setState(state+1);//锁数量+1 15 return true; 16 } 17 return false;//获取失败 18 } 19 20 @Override 21 protected boolean tryRelease(int arg) { 22 //当前线程不是存储线程 23 if(Thread.currentThread() != getExclusiveOwnerThread()){ 24 throw new RuntimeException(); 25 } 26 int state = getState()-arg;//锁数量-1 27 boolean flag = false; 28 if(state==0){//锁数量为0 29 setExclusiveOwnerThread(null);//独占锁为null,表示可以让其他线程进来竞争获取资源了 30 flag=true; 31 } 32 setState(state);//更新状态 33 return flag; 34 } 35 36 public ConditionObject newConditonObject(){ 37 return new ConditionObject(); 38 } 39 } 40 @Override 41 public void lock() { 42 myAQS.acquire(1); 43 } 44 45 @Override 46 public void lockInterruptibly() throws InterruptedException { 47 myAQS.acquireInterruptibly(1); 48 } 49 50 @Override 51 public boolean tryLock() { 52 return myAQS.tryAcquire(1); 53 } 54 55 @Override 56 public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { 57 return myAQS.tryAcquireNanos(1,unit.toNanos(time)); 58 } 59 60 @Override 61 public void unlock() { 62 myAQS.release(1); 63 } 64 65 @Override 66 public Condition newCondition() { 67 return myAQS.newConditonObject(); 68 } 69 }
作者:huangrenhui
欢迎任何形式的转载,但请务必注明出处。
如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】。
如果,您希望更容易地发现我的新博客,不妨点击一下左下角的【关注我】。
如果,您对我的博客所讲述的内容有兴趣,请继续关注我的后续博客,我是【码猿手】。
如果,您希望更容易地发现我的新博客,不妨点击一下左下角的【关注我】。
如果,您对我的博客所讲述的内容有兴趣,请继续关注我的后续博客,我是【码猿手】。
限于本人水平,如果文章和代码有表述不当之处,还请不吝赐教。