【问题标题】:Replace AtomicBoolean by primitive type when only the get() and set() methods are used?仅使用 get() 和 set() 方法时,将 AtomicBoolean 替换为原始类型?
【发布时间】:2023-03-13 22:20:02
【问题描述】:

我的代码包含一些AtomicBoolean 字段。仅调用这些字段的get()set() 方法。

这些字段的类型可以安全地替换为原始布尔值吗?

我的意思是,原始布尔值的赋值和访问操作是 Java 中的原子操作。从这个角度来看,我看不出有任何理由使用AtomicBoolean

在我的理解中,AtomicBoolean 只有在使用像 compareAndSet 这样结合比较和访问的方法时才有意义。我错了吗?你能解释一下为什么吗?

【问题讨论】:

  • 太宽泛而没有显示有问题的代码,但一般答案是否定的。
  • 您是否从不同的线程访问字段?
  • 有两种竞争条件:check-then-act 和 read-modify-write。如果您将 AtomicBoolean 替换为原始布尔值,您的问题将是前者。
  • 是的,我正在从不同的线程访问它们
  • @mre 为什么会发生这种情况?该代码未使用compareAndSet() 或任何类似方法。

标签: java atomic atomicboolean


【解决方案1】:

原子变量在Java Concurrency in Practice中被描述为“更好的易失性”(参见第 15.3 节)。这是本书的摘录:

原子变量类提供volatile的泛化 支持原子条件 read-modify-write 操作的变量。 AtomicInteger 表示 int 值,并提供 getset 具有与读取和写入相同内存语义的方法 volatile int.

应用于您的情况,这意味着如果您仅使用AtomicBooleanget()set() 方法,则可以安全地将它们替换为对volatile boolean 的读写操作。

volatile 需要保证所有线程都能看到变量的最新值。回到 Java 并发实践(第 3.1.4 节):

当一个字段被声明为volatile 时,编译器和运行时被放入 请注意,这个变量是共享的,对它的操作应该 不会与其他内存操作一起重新排序。 Volatile 变量是 没有缓存在寄存器或缓存中,它们对其他人隐藏 处理器,因此读取volatile 变量总是返回最多 任何线程最近写的。

【讨论】:

  • 感谢您的回答。你能解释一下为什么没有 volatile 的原始布尔值在我的情况下不起作用吗?或者您能否描述在我的案例中使用原始布尔值时可能导致问题的场景?
  • @eztam AtomicBoolean 作为参考传递。如果您将 boolean 传递给两个线程,它们将不再具有共享值。
  • @eztam。使用原始boolean 可能导致问题的唯一情况是在 check-then-act 操作中使用它。在这种情况下,您应该使用AtomicBoolean(或使用同步)。
  • @PeterLawrey 好点!但我只是在谈论访问同一类的字段。 AtomicBooleans 不会在任何地方传递。
  • @eztam Volatiles 不保证原子性。他们只保证可见性
【解决方案2】:

这些字段的类型可以安全地替换为原始布尔值吗?

简单原语booleanAtomicBoolean 不同(后者在多线程环境中提供原子访问)。

但是,安全的替代方法可能是使用volatile boolean,它也可以提供原子访问,但我建议您保留AtomicBoolean 原样(因为它提供了额外的 API 方法,以防您将来可能会使用它)。

【讨论】:

  • 谢谢,我很清楚原始布尔值和原子布尔值之间的区别。但是您能解释一下为什么在我的个人情况下无法替换它们吗?
  • 你能告诉我你为什么要这样做吗?我的意思是你到底期待什么?因为访问已经是原子的(因为您使用的是AtomicBoolean),所以您为什么要更改现有行为?
【解决方案3】:

答案是否定的。你可以在这里找到原因Why can't AtomicBoolean be a replacement for Boolean?

【讨论】:

  • 那篇文章是关于相反的替换:用AtomicBoolean替换Boolean
  • 是的。但是,当您阅读提供的答案时,说明 AtomicBoolean 是一个为并发目的而设计的单独类。所以 AtomicBoolean 是线程安全的。所以你不能用原始布尔值替换它。
  • 如果您不想在代码中使用 AtomicBoolean,您可以使用原始布尔值,但您应该使用同步自己处理线程安全属性。
  • 读写原语volatile boolean 也将是线程安全的。 AtomicBoolean 对于应该以原子方式执行的 check-then-actcompound 操作很有用(例如 getAndSet()compareAndSet())。
  • @PavloViazovskyy 我同意这一点。但正如我解释的那样,代码没有使用getAndSet()compareAndSet() 或类似的东西。问题是只调用get()set()的情况。
猜你喜欢
  • 2012-07-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-14
  • 2011-02-28
  • 2017-04-16
  • 2013-06-19
  • 2013-12-26
相关资源
最近更新 更多