juc_AQS|LockSupport
2021-07-06 16:36:58 0 举报
AQS与LockSupport的源码解析
作者其他创作
大纲/内容
false
true
pred.next = node;将当前节点设置为原尾节点的下一个节点
addWaiter(Node mode)
state = 1
node.prev = pred; 将当前节点的上一个节点设置为尾节点
线程A
Lock lock = new ReentrantLock();Condition condition = lock.newCondition();
线程3
unlock
head(头节点) != null&&头节点 的 waitStatus != 0
可以理解为:发放通行证
signal
//模板模式 protected boolean tryRelease(int arg) { throw new UnsupportedOperationException(); }
boolean
boolean failed = true;
开始
双向队列
Node p = node.pred;当前节点的上一个节点赋值给 p
线程2
可重入锁,就是获取到锁的线程,可以再次调用相同的锁,而其他线程无法获取已经有锁的状态
Node s = tail
ReentrantLock
Node
nextc < 0
没有获取到锁的线程,进入等待队列,通过自旋判断锁是否被释放,如果释放,则自己获取锁,如果不没有释放,则继续自旋。
font color=\"#4d9900\
ReentrantLock lock = new ReentrantLock();
源码解析
LockSupport.unpark(s.thread);解锁 s 线程
Node t = tail;
protected final boolean tryRelease(int releases) { //releases = arg = 1; int c = getState() - releases; //c = 锁状态值 - arg if (Thread.currentThread() != getExclusiveOwnerThread()) //如果 当前线程 != 获取锁的线程 throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { //如果 c == 0;表明锁状态值为 0,无人持有锁 free = true; setExclusiveOwnerThread(null); //设置锁持有者 为 null } setState(c); //设置状态值 return free; }
tryRelease(arg)尝试释放锁
AQS:抽象队列同步器,除了java自带的synchronized关键字之外的一种锁机制
Node head头
取反
Sync
c == 0
抽象方法有具体的实现:公平锁与非公平锁
unparkSuccessor(head);解阻塞 h节点
FairSync公平锁
addWaiter(Node mode) 逻辑
return false
return unsafe.font color=\"#990000\
NonfairSync非公平锁
这个方法 compareAndSwapInt 的意思是:比较并交换。其中 stateOffset 为实际值,expect 为期望值,update 为更新值。就是比较 实际值 与 期望值 是否相同,如果相同 则将 更新值 赋值给 实际值,返回 true。如果不等,取消赋值,返回 false。
tail != null &&tail != head
Lock方法的具体实现
方法
private Node enq(final Node node) { //node 当前线程节点 for (;;) { // for (;;) {} 相当于 while 循环 Node t = tail; //将 尾节点 赋值给 t if (t == null) { // Must initialize //初始化节点;如果 尾节点 是 null 的 if (compareAndSetHead(new Node())) //比较并 new Node() 设置为 head 头节点。compareAndSetHead 底层传值:实际值:头节点 期望值:null 更新值:new Node() tail = head; //将 头节点 赋值给 尾节点;即头 指向 尾 } else { //如果 尾节点 不是 null node.prev = t; font color=\"#000099\
true && true
return node;返回当前节点
sync.release(arg 1);
获取锁的线程修改锁的状态,state 由 0 => 1,当相同的线程再获取锁时,可以继续获取到,只是将 state 的值再加 1,这就是可重入。注意一点,获取多少次锁,则释放多少次锁,否则其他线程在获取锁时,查询锁状态 state 值不为 0,则其他线程获取不到锁。
pred != null
默认
tail.waitStatus <= 0
从等待队列中删除获得锁的线程
ReentrantLock 中的方法
设置 当前线程 持有锁
将 当前线程 设置为独占节点Node pred = tail;
boolean interrupted= false;
lock.unlock();
持有锁的线程
Lock
AQS = state + CLH变种的队列
AQS 中的方法
return true
//真实的逻辑 protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); }
next后
等待队列
falsearg = 1
private final boolean parkAndCheckInterrupt() { //阻塞当前线程进入排队等候队列 LockSupport.park(this); //当前线程阻塞,使用的是LockSupport.park() 方法 return Thread.interrupted(); //当 当前线程解阻塞之后,检查线程是否中断,是 返回 true 否 返回 false }
sync.lock();
state = nextc
① free = true;② 设置当前没有线程持有锁
即将获取锁的线程
Thread
锁状态
addWaiter(Node.EXCLUSIVE)
继承
head.waitStatus < 0
prev前
end
加入等待队列末尾
parkAndCheckInterrupt()
线程C
c = state - arg
当前线程 != 获取锁的线程
acquireQueued(font color=\"#0000ff\
compareAndSetState 的具体实现
LockSuppor:等待唤醒机制(wait | notify)
1.不需要锁块就可以阻塞线程和唤醒线程2.不区分是先阻塞还是先解阻塞
return interrupted;
尝试释放锁
设置头节点为new Node();
设置当前线程节点为头节点
final boolean nonfairTryAcquire(int acquires) { //非公平锁尝试获取锁 final Thread current = Thread.currentThread(); //将 当前线程 赋值给 current int c = getState(); //将 AQS 的 state 值(状态值)赋值给 c if (c == 0) { font color=\"#000099\
设置 当前线程 持有锁;此时 state = 1;
nextc = c + 1
return
① !tryAcquire(arg)span style=\"font-size: inherit;\
s != null
Node tail尾
tryAcquire(arg)尝试获取锁1.获取当前线程 current2.获取 state 状态值 c
异常
wait
tail = head;尾节点也是空节点
lock.lock();
内部类
lock()
return t;返回原尾节点
可以理解为:需要通行证才放行
d
abstract void lock();
node:当前线程节点
t == null
acquire(arg = 1);
waitStatus
AQS内部主要方法总结
是
node.prev = t;当前节点前一个节点为 t 节点(即之前的尾节点
span style=\"font-size: inherit;\
两个方法
//这里用到了设计模式的模板模式 protected boolean tryAcquire(int arg) { throw new UnsupportedOperationException(); }
① tryAcquire 尝试获取锁
state
将permit由1变为0,如果本身是0,则阻塞等待
否
是不是自己之前持有锁
selfInterrupt();线程自中断
head.status = 0
是通过Node 封装的节点Node<Thread>
解锁
failed = false;
enq 内部逻辑
synchronized
线程1
tail = tail.prev
park()阻塞
ReentrantLock的子类
enq(node)还没有队列,需要初始化生成一个队列
AQS 组成部分
setExclusiveOwnerThread(Thread.currentThread());设置当前线程持有独占模式(即当前线程获得锁)
LockSupport
AQS
boolean free = false;
ReentrantLock的方法
从 ReentrantLock 解读 AQS 源码
AQS 中 state 的默认值 0
NonfairSync非公平锁默认:state = 0;
unpark(Thread thread)解阻塞
顶级的抽象类
t.next = node;将当前节点设置为原尾节点的下一个节点
head.next == null||head.next.waitStatus > 0
p 节点的下一个节点设置为 null
线程B
CAS,设置状态值由 0 => 1
state = c
将permit变为1
await
notify
1. p == head&&2. tryAcquire(arg)
permit = 0许可证只能是0,1
0 条评论
下一页