AQS
2021-01-27 23:53:06 0 举报
AQS加锁和解锁的源码流程
作者其他创作
大纲/内容
线程B
//设置当前线程为B线程final Thread current = Thread.currentThread();
setExclusiveOwnerThread(Thread.currentThread())
将当前线程封装成一个Node
Thread=ThreadBwaitstatus=0
是
再次进入循环后,节点获取到锁,移出队列
sync.lock()
tail
否
Node pred = tail此时tail为空,pred也是null
唤醒此处的阻塞,使线程B能够获取到锁
head
Thread=ThreadCwaitstatus=0
线程A释放锁
state==0
next
if (compareAndSetHead(new Node())){ tail = head;}
tryAcquire
线程C
抢占锁失败后阻塞shouldParkAfterFailedAcquire
判断head!=null且waitStatus!=0
哨兵节点(占位符)Thread=nullwaitstatus=0
线程A
Thread=ThreadCwaitstatus=-1
state == 0表示线程A刚好执行完释放了锁,B线程直接获取锁
state+=1
tail是否为空
Thread=nullwaitstatus=0
返回false
AQS.tryAcquire(1)
线程C对应的Node入列
AQS.release(1)
再次抢占锁
线程B的Node入队
Node h = head; //当前clh队列中,head指针指向哨兵Node//哨兵Node非空,且waitStatus=-1if (h != null && h.waitStatus != 0){ unparkSuccessor(h);}
state=1
线程C的Node入列后的CLH
lock.lock()
unlock()
state=0
线程B已经入列,tail指向线程B的Node节点,因此tail不为null
阻塞并且检查线程是否中断parkAndCheckInterrupt
current == getExclusiveOwnerThread()
自旋循环操作
抢占成功
修改失败,表示已经有线程占用了锁
创建空的Node节点
private final boolean parkAndCheckInterrupt() { LockSupport.park(this); //阻塞当前线程(线程B) return Thread.interrupted(); //判断线程是否中断}
模拟三个线程争夺资源:Thread AAA 暂停200S,模拟长时间业务Thread BBBThread CCC
是否公平锁
unparkSuccessor(head)
可重入锁判断
CLH队列
CAS设置head指针为新Node
acquire(1)
哨兵节点(占位符)Thread=nullwaitstatus=-1
NonfairSync.tryAcquire(1)
tail指针是否为空
线程B入队完成后的CLH队列
tryRelease(1)
执行业务流程
节点移出队列
Thread=ThreadBwaitstatus=-1
FairSync.tryAcquire(1)
此时的CLH队列
private void setHead(Node node) { head = node; node.thread = null; node.prev = null;}
p==head
nonfairTryAcquire(1)
Node入对enq(node)
FairSync.lock()
if (current == getExclusiveOwnerThread()) { //是否是已经占有锁的线程,重入锁 int nextc = c + acquires; //state = 1+1 if (nextc < 0) // overflow throw new Error(\"Maximum lock count exceeded\"); setState(nextc); //设置state的值,在原有的基础上+1 return true;}
线程A又再一次获取到了锁
CAS设置state
acquireQueued(Node)
addWaiter(Node.EXCLUSIVE)
true
此时state=1且非重入的情况下,返回false,继续向下执行
返回入列的Node
Sync继承自AQS
protected final boolean tryRelease(int releases) { int c = getState() - releases; //state值减1 if (Thread.currentThread() != getExclusiveOwnerThread()) //判断当前线程是否是独占锁的线程,不是抛出异常 throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { //state值变为0,那么就将占用锁的线程设置为null free = true; setExclusiveOwnerThread(null); } //发生锁重入的情况下,state会大于0 //重新设置state的值 setState(c); return free;}
CAS的方式将AQS中的state值改为1,修改成功
CLH队列,此时队列为空,只有一个head和tail
NonfairSync.lock()
获取Node的前置节点p
线程B和线程C在此处park(Thread A),等待线程A执行完成后使用unpark唤醒其中一个,唤醒流程参考unlock()
prev
当前为线程B,且A线程业务未执行完,因此此处返回false
ReentrantLock.lock()
0 条评论
下一页