【发布时间】:2022-01-20 14:37:46
【问题描述】:
我知道下一个场景:(奇怪的格式,我知道)
private final AtomicBoolean aBoolean = new AtomicBoolean(true);
public void doSomething() {
if (
aBoolean.get() // line A
&& // line B
aBoolean.compareAndSet(true, false) // line C
) {
System.out.println("Was true!")
}
}
如果线程#1 和线程#2 同时输入doSomething(),就会发生这种情况:
-
线程#1 和线程#2 将
aBoolean.get()读取为== “真”同时。 -
两者都将执行“&&”运算符。
-
CMPXCHG 指令同时为两个线程启动:
3.1 本地使用LOCK前缀
3.2 线程 #1 或 #2 先到达,赢得比赛。
3.3 获胜线程比较(aBoolean == true 吗?)这将返回“true”,因此 aBoolean 将设置为“false”。
3.4 aBoolean 现在为假。
3.5 丢失的线程比较(是 aBoolean == true 吗?)这将返回“false”,从而使任何进一步的操作短路。
-
获胜线程将打印“是真的!”。
从“失败”线程的角度来看,“A 行”中的第一个 aBoolean.get() 是……假设……一个“谎言”。
现在假设执行可以发生在运算符之间,就像上面示例中所做的那样,让我们为第二种情况添加第二种方法:
public void unluckySet() {
aBoolean.set(false);
}
假设线程 #3 恰好在我们的“获胜线程”到达执行“&&”的“B 行”的确切时刻到达并执行unluckySet()。
如果获胜线程到达“B 行”,则意味着它到达“A 行”,aBoolean 为“真”。
我的问题是:
CMPXCHG 是否会将更新后的值正确读取为“假”?这意味着.set() 也被与compareAndSet() 相同的锁持有。
并发和线程之间:
运算符(“&&”、“||”、“==”、“=”,甚至可能是“return;”?这样两者都以交错的方式结束,防止可能的冲突?
【问题讨论】:
-
是的,他们可以。原子值仅在单个操作中是原子的。
atomicOp1() && atomicOp2()是 2 个独立的原子操作 -
请注意,
AtomicBoolean没有什么特别之处,jvm 不会以任何方式特殊对待它们,因此与它们的两个独立交互就是:独立。 -
谢谢@Felix 我现在正在查看一些代码 [JCTools Java Concurrency Tools for the JVM。 ](github.com/JCTools/JCTools/blob/master/jctools-core/src/main/…),我看到在“CAS_key(”的自旋锁开始的第 666 行和甚至不在自旋锁中的第 775 行“CAS_val(”之间发生了太多事情,我猜那不是完全线程安全...正确吗?该代码已被分叉 444 次和 2.9k 星评级。
-
...更正,有一个自旋锁,但在形式上是一种自引用方法...这仍然不完全安全,因为即使在运算符之间也可能发生变化...
-
嗯,像
int dummy = DUMMY_VOLATILE;这样的行表明这段代码被设计为恰好在特定实现下工作,充其量。
标签: java multithreading concurrency atomic interleave