AQS加锁过程
2023-12-26 09:20:05 19 举报
AQS加锁过程
作者其他创作
大纲/内容
Sync extend AQS
lock()
thread = nullprev next
ReentrantLock有个Sync的静态抽象类,内部的FairSync/NonfairSync继承了Sync,让ReentrantLock可以在构造方法中给sync属性赋公平锁和非公平锁,默认是非公平锁
3
AbstractQuequSynchronizer
release(1)
next
nonfairTryAcquire(1)
thread = t2prev next
2循环
pred
2
prev
ws = 0
第二个及往后进入队列的线程的阻塞场景shouldParkAfterFailedAcquire:在尝试获取锁后应该阻塞线程吗?参数:前节点,当前节点将前节点的ws改为-1,return false,进入第二次循环
acquired(1)
parkAndCheckInterrupt:park线程并检查中断park:调用LockSupport.park(this),将线程阻塞
thread 2
N
state已经改为0了,阻塞的线程被唤醒,回到accquireQueued的死循环加锁的流程
将线程节点入队
enq(node)
state = 1 execlusiveOwnerThread = thread 0
true
2:CAS
ReentrantLock
Sync sync;sync.release(1);
head tail
当前线程是第一个进入双向链表的线程,需要完成FIFO双向链表的初始化工作;取到尾节点tail如果尾节点还是为null 创建一个空节点new Node()并赋给尾节点进入第二次for循环,此时尾指针不为null,进入else代码块 当前节点的前节点指向尾节点 调用compareAndSetTail来将尾节点改为当前节点 成功则将前尾节点next指向当前节点 返回当前节点
thread = t1prev next
将当前线程封装成一个Node渠道尾节点 pred = tail如果pred != null,说明已经有排队的节点在排队了将当前节点的prev指向尾节点调用compareAndSetTail来将尾巴节点改为当前节点成功则前尾节点的next指向当前节点,返回当前节点
AQS(Abstract Queue Synchronizer,抽象队列同步器)框架:通过一个volatile修饰的state来表示同步的状态,使用内置的一个FIFO队列来完成抢占资源的排队状态,把每个未抢占资源的线程封装成双向链表的一个节点,各线程通过CAS来修改state的值。整个过程都围绕着自旋锁、CAS和LockSupport类提供的park/unpark来完成线程的睡眠与唤醒。
1循环
第一个进入队列的线程的阻塞场景参数node 为t1节点node,arg = 1在for循环里面取得傀儡结点p;判断 p == head表示是第一个排队的->尝试获取锁(非公平锁和公平锁的tryAcquire方法不一样),公平锁多了个!hasQueuedPredecessors() && ; 可以获取锁则将t1的node设为头节点并将p.next = null来help gc 并 return false否则走第二及往后节点走的流程
第一个进入队列的线程的阻塞场景参数node 为t1节点node,arg = 1在for循环里面取得傀儡结点p;判断 p == head表示是第一个排队的->尝试获取锁; 可以获取锁则将t1的node设为头节点并将p.next = null来help gc 并 return false否则走第二及往后节点走的流程
唤醒节点的处理器参数:傀儡节点 h1.拿到傀儡节点的ws状态值-1;2.判断ws < 0 ? CAS设置ws的值为0;3.拿到傀儡节点的下一个节点 s;4.判断 s == null 或者 s.waitStatus > 0,???不知道什么意思......5.如果s != null,LockSupport.unpark(s.thread)唤醒线程;
程序阻塞在这里后将,等待其他线程释放锁(将state改为0,并unpark当前线程来唤醒),继续走accquireQueued方法中的死循环来替换傀儡节点,执行线程
shouldParkAfterFailedAcquire
线程1排队结果
unparkSuccessor(h)
ws = -1
null
thread 1
链表的tail不为空->2循环
unlock
第二个及往后进入队列的线程的阻塞场景shouldParkAfterFailedAcquire:在尝试获取锁后应该阻塞线程吗?参数:前节点,当前节点ws == -1 return true,表示应该park当前node线程
1
在addWaiter方法执行将线程节点入队后需要将节点线程阻塞
rerurn false
thread 0
Sync sync;sync.lock();
!tryAcquire(1)
lock.lock()
链表的tail不为空
尾节点为空,即这是第一个排队的线程
addWaiter(Node.EXCLUSIVE)
2循环:CAS
Y
addWaiter(node)
addWaiter.enq(node)
h != null &&h.waitStatus != 0
&&
selfInterrupt()
tryRelease(1)
线程2排队结果
CAS修改state值成功,即占有锁成功,设置占有线程属性
0 条评论
回复 删除
下一页