3

如果我有一个 volatile 布尔值(我们称它为有效),那么以下代码在 Java 中是线程安全的吗?

if (valid)
  return;
valid = true;

或者,我是否需要同步,因为仅当它为假时才将有效设置为真(因此有效的集合取决于其当前值)?

4

7 回答 7

8

这需要同步,因为如果一个线程将 valid 评估为 false,然后在分配之前暂停执行,那么另一个线程会出现并检查 valid 为 false,在将 valid 设置为 true 之前,您将有两个线程运行以下代码从这里(大概你不想要)。

于 2009-12-13T18:15:29.297 回答
5

使用 AtomicBoolean。可以同时检查和设置实例。

于 2009-12-13T18:33:05.707 回答
4

它不是线程安全的。但如果这是整个代码,那就没关系了。

于 2009-12-13T18:11:40.070 回答
2

编辑:一个全面的优越替代方案是AtomicBoolean,它使用低级操作来实现不同步的条件更新。

对标志有两个单独的(即非原子的)访问,因此同步是必要的,除非这个线程是唯一对标志进行写操作的线程。即使那样,为了确保将来发生变化,进行同步也可能会很好。

于 2009-12-13T18:15:41.180 回答
1

您的代码不是线程安全的,但它确实取决于您的其他代码是否安全。

您是否要求以下代码valid = true仅由单个线程执行一次?如果是这样,那么您的代码是不安全的,因为任何数量的线程都可以读取 的falsevalid,然后最终将其设置为true。例如:

if (valid)
  return;
// Imagine every single one of your threads stops and blocks here.
// They will all wake up again and set valid to true and then
// execute the code to follow.
valid = true;

但是,如果您只想保证之后的代码最多由任何valid = true线程执行一次……那么您所拥有的就可以了。但如果这是您需要的行为,我会通过其他方式实现,因为在这种情况下使用看起来就像您不知道自己在做什么。例如,您可以不跨线程共享变量,并允许每个线程只执行一次代码。volatilevalid

此外,当在推理同步和易失性时有疑问......只需使用同步。它通常更清晰,并且会从 using 中得到你想要的一切volatile,除了它更容易推理代码的工作原理。

于 2009-12-13T18:38:25.960 回答
1

线程安全是系统范围的属性。您不能孤立地查看一段代码并将其称为线程安全/不安全。这取决于其他线程如何与之交互以及一致性要求是什么。话虽如此,大多数线程安全设计都有 while() 循环而不是 if() 块,因此,您的设计很可能是不正确的:)

于 2009-12-13T19:18:04.903 回答
1

根据 Brian Goetz 的伟大论文 https://www.ibm.com/developerworks/java/library/j-jtp06197/ “您只能在有限的情况下使用 volatile 变量而不是锁。以下两个标准都必须满足 volatile 变量以提供所需的线程安全性:

  • 对变量的写入不依赖于其当前值。
  • 该变量不参与其他变量的不变量。

基本上,这些条件表明可以写入 volatile 变量的有效值集独立于任何其他程序状态,包括变量的当前状态。”因此它必须与锁同步。它不是线程安全的,因为是。

于 2013-08-30T16:46:23.527 回答