【问题标题】:How to manage the concurrent access in AtomicLong class?如何管理 AtomicLong 类中的并发访问?
【发布时间】:2022-10-01 09:37:52
【问题描述】:

研究原子类我发现了这段代码:

public class AtomicCounter {

private AtomicLong count = new AtomicLong(0);

public void increment() {
    boolean updated = false;
    while(!updated){
        long prevCount = count.get();
        updated = count.compareAndSet(prevCount, prevCount + 1);
    }
}

public long count() {
    return count.get();
}

我问自己如果发生以下情况怎么办:

  1. 在线程 A 中,在调用 compareAndSet 方法后,布尔值更新为 true。

  2. 在线程 B 中,指令 boolean updated = false; 被执行,并且更新的布尔值再次更改为 false

  3. 在线程 A 中,循环 while 检查最近更改为 false 的布尔值更新的值,因此将发生另一个飞跃。

    在这种情况下,即使线程 A 已经将 updated 的值更改为 true ,线程 A 也会进行新的飞跃,因为在此更改和检查更新的时间之间,另一个线程 B 已将更新的值更改为错误的。 这种情况在多大程度上是真实的?

  • 我格式化了你的编号。 Stack Overflow 确实通过其 Markdown 风格支持基本的 HTML。我建议您在有用的地方利用它。
  • 线程共享AtomicCounter,因此它们也会共享它的count 变量。 updated 是本地的意味着它只存在于方法当前执行的上下文中。即使在同一个线程中递归调用该方法,每次都会有一个新的本地版本。如果你递归太深,你会得到一个stackoverflow,因为它们太多了,无法放入内存(或者确切地说是堆栈)。

标签: java multithreading


【解决方案1】:

局部变量不是线程间共享

您误解了 local variables 如何与 threads 一起工作。

? 每个线程都有自己的局部变量。

局部变量保存在call stack 上。每个线程都有自己的调用堆栈。所以在你的场景中,updated 变量存在。

请参阅问题Why are local variables thread safe in Java

所以你的线程一个每个都有自己的updated 变量。一个线程更改updated 的值不会影响另一个线程的updated 变量。

这种情况在多大程度上是真实的?

步骤#1是正确的。

第 2 步和第 3 步不正确。

【讨论】:

  • 如果 A 和 B 都有自己的更新变量,那么我假设当我们调用 System.identityHashCode(updated) 时,我们会得到不同的 ID 编号,但事实并非如此(至少对于我的测试而言)。为什么 ?
  • @taherbouali 变量没有身份。您只是通过Boolean.valueOf() 将变量装箱到常量引用。
  • @taherbouali boolean updated 不是对象。它是一个原始的。 System.identityHashCode 方法采用对象引用,而不是原语。
  • @shmosel 有趣的解释。我想知道如何将原语传递给该方法将通过编译器。谢谢你。
  • @taherbouali 作为shmosel commented,可能的解释是您传递给System.identityHashCode 的原始boolean 值是自动装箱的,可能是常量Boolean.TRUEBoolean.FALSE 对象。因此,对同一常量 Boolean 对象的两个引用将显示相同的标识。这与您现有的两个 updated 变量无关。
猜你喜欢
  • 2019-06-23
  • 1970-01-01
  • 2011-04-03
  • 1970-01-01
  • 2019-07-18
  • 1970-01-01
  • 2018-02-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多