AQS之ReentrantLock源码
2023-08-22 18:08:05 12 举报
AQS之ReentrantLock源码
作者其他创作
大纲/内容
执行业务代码
addWaiter(Node.EXCLUSIVE)
waitStatus=0
acquire(1);
setHead(node);
if (h != null && h.waitStatus != 0)
初始=0
head
pre
刚开始tail=null
创建节点
并且再次尝试获取锁
Node p = node.predecessor();
arg=1
int ws = pred.waitStatus;
lock = new ReentrantLock(true);
thread = t1
return false
thread = null
&& tryAcquire(arg))
设置中断标志,线程仍会继续运行Park不再起作用,让线程优雅的中断
this.waitStatus=0;this.prev=null;this.next=null;this.nextWaiter = null;this.thread = t1;
p.next = null; // help GCfailed = false;return interrupted;
if span style=\"font-size: inherit;\
3.1、获取队列中当前线程的前驱节点
执行业务代码逻辑......
文本
false
Node h = head;
selfInterrupt();
3、阻塞线程之前判断是否需要再次尝试获取锁
释放锁
tail
唤醒下一个线程
自旋第一轮循环前驱节点的状态变为-1,表示下一个线程可唤醒
因为加锁成功,当前线程属性置空并且变成队头
Node pred = tail;
next
Thread.currentThread().interrupt();
return true;
lock.unlock();
设计精髓1)cas构建队列2)自旋保证入队成功
return true
false,阻塞线程
如果是true表示当前线程已中断
判断线程前驱节点的状态
阻塞线程之前,将它的前驱节点waitStatus修改为-1,表示当前线程可被唤醒
自旋
SIGNAL(-1)
true
如果队列中当前线程的前驱节点就是队头,表示当前线程排在队列第一个。
获取锁失败,阻塞线程
阻塞当前线程
获取锁成功
return node
自旋第二轮循环
LockSupport.park(this)
unparkSuccessor(h);
t1线程进入队列排队
tryAcquire(arg)
Node p = prev;
-1
加锁成功
唤醒之后,测试当前线程是否被是中断唤醒的并清除中断标记
return Thread.interrupted();
t1线程入队
&&parkAndCheckInterrupt())
目的就是避免不必要的线程阻塞,阻塞线程再唤醒线程涉及到用户态和内核态的切换是一个比较重的操作
return p
if (tryRelease(arg))
FairSync.lock
sync.release(1);
interrupted = true;
lock.lock();
if (p == head
加锁失败2、t1线程进入等待队列
enq(node);//入队
初始化队列
符合允许可中断特性:中断唤醒之后,去获取锁
head = node;node.thread = null;node.prev = null;
1、t1线程尝试加锁
用图演示
公平锁源码分析
0 条评论
下一页