当前位置:网站首页>Juc并发编程07——公平锁真的公平吗(源码剖析)
Juc并发编程07——公平锁真的公平吗(源码剖析)
2022-04-23 09:55:00 【半旧518】
先来回顾下公平锁的tryAcquire代码。
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() && //注意这里,一开始会查看是否有节点处于等待
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
重点关注注释代码处,如果hasQueuedPredecessors出现误判会怎么样呢?公平锁是不是就不公平了呀。那我们来研究下hasQueuedPredecessors,是不是真有百密一疏的情况。
假如线程1已经持有锁了。这个该时候线程2来获取锁,走到hasQueuedPredecessors()返回false,接着往后面执行CAS,肯定执行失败,因为现在锁被线程1占有,返回aquire方法。
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
接着走就是走到addWaiter的enq方法。线程2进入等待队列。
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) {
// 此时等head、tail为空,满足`t==null`的条件。
if (compareAndSetHead(new Node())) //这里没有其它线程争抢,成功
tail = head; // 设置成功
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
假设线程2走到注释截至处,现在有一个线程3来抢锁。当它判断等待队列时hasQueuedPredecessors会返回false,因为h==t。
public final boolean hasQueuedPredecessors() {
Node t = tail;
Node h = head;
Node s;
return h != t && //不满足条件
((s = h.next) == null || s.thread != Thread.currentThread());
}
那么问题来了,实际上等待队列中应该有线程2,现在我们却得出了等待队列为空的判断呀,线程3不的直接走CAS吗,万一线程1刚好释放锁了,线程3就插队了阿。由此可见,公平锁并不公平。
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
用一张图来总结下上面的过程。

公平锁公不公平关键就在与hasQueuedPredecessors是否会出现误判。
版权声明
本文为[半旧518]所创,转载请带上原文链接,感谢
https://blog.csdn.net/qq_41708993/article/details/124336106
边栏推荐
- 杰理之通常程序异常情况有哪些?【篇】
- C language: expression evaluation (integer promotion, arithmetic conversion...)
- Introduction to graph theory -- drawing
- Rain produces hundreds of valleys, and all things grow
- 通过流式数据集成实现数据价值(5)- 流分析
- ABAP 7.4 SQL Window Expression
- [COCI] Vje š TICA (subset DP)
- Leetcode0587. Install fence
- Pyqt5与通信
- MapReduce核心和基础Demo
猜你喜欢

2022年广东省安全员A证第三批(主要负责人)考试试题及答案
MapReduce计算流程详解

杰理之更准确地确定异常地址【篇】

Cloud identity is too loose, opening the door for attackers

"Gu Yu series" airdrop

Leetcode question bank 78 Subset (recursive C implementation)

《Redis设计与实现》

论文阅读《Integrity Monitoring Techniques for Vision Navigation Systems》——3背景

【无标题】

2022年制冷与空调设备运行操作考试练习题及模拟考试
随机推荐
CSP认证 202203-2 出行计划(多种解法)
杰理之栈溢出 stackoverflow 怎么办?【篇】
[untitled]
Es aggregation aggregation analysis
第三章 启用和调整IM列存储的大小(IM-3.1)
DBA常用SQL语句(1)— 概况信息
深度选择器
SAP CR transmission request sequence and dependency check
The central control learning infrared remote control module supports network and serial port control
2022年制冷与空调设备运行操作考试练习题及模拟考试
论文阅读《Integrity Monitoring Techniques for Vision Navigation Systems》——3背景
Compile and debug mysql8 with clion under MacOS x
SAP salv14 background output salv data can directly save files and send emails (with sorting, hyperlink and filtering format)
《Redis设计与实现》
Redis 异常 read error on connection 解决方案
Easy to understand subset DP
通过流式数据集成实现数据价值(4)-流数据管道
Less than 100 secrets about prime numbers
通过流式数据集成实现数据价值(2)
第一章 Oracle Database In-Memory 相关概念(续)(IM-1.2)