如果我有一个 volatile 布尔值(我们称它为有效),那么以下代码在 Java 中是线程安全的吗?
if (valid)
return;
valid = true;
或者,我是否需要同步,因为仅当它为假时才将有效设置为真(因此有效的集合取决于其当前值)?
如果我有一个 volatile 布尔值(我们称它为有效),那么以下代码在 Java 中是线程安全的吗?
if (valid)
return;
valid = true;
或者,我是否需要同步,因为仅当它为假时才将有效设置为真(因此有效的集合取决于其当前值)?
这需要同步,因为如果一个线程将 valid 评估为 false,然后在分配之前暂停执行,那么另一个线程会出现并检查 valid 为 false,在将 valid 设置为 true 之前,您将有两个线程运行以下代码从这里(大概你不想要)。
使用 AtomicBoolean。可以同时检查和设置实例。
它不是线程安全的。但如果这是整个代码,那就没关系了。
编辑:一个全面的优越替代方案是AtomicBoolean
,它使用低级操作来实现不同步的条件更新。
对标志有两个单独的(即非原子的)访问,因此同步是必要的,除非这个线程是唯一对标志进行写操作的线程。即使那样,为了确保将来发生变化,进行同步也可能会很好。
您的代码不是线程安全的,但它确实取决于您的其他代码是否安全。
您是否要求以下代码valid = true
仅由单个线程执行一次?如果是这样,那么您的代码是不安全的,因为任何数量的线程都可以读取 的false
值valid
,然后最终将其设置为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
线程执行一次……那么您所拥有的就可以了。但如果这是您需要的行为,我会通过其他方式实现,因为在这种情况下使用看起来就像您不知道自己在做什么。例如,您可以不跨线程共享变量,并允许每个线程只执行一次代码。volatile
valid
此外,当在推理同步和易失性时有疑问......只需使用同步。它通常更清晰,并且会从 using 中得到你想要的一切volatile
,除了它更容易推理代码的工作原理。
线程安全是系统范围的属性。您不能孤立地查看一段代码并将其称为线程安全/不安全。这取决于其他线程如何与之交互以及一致性要求是什么。话虽如此,大多数线程安全设计都有 while() 循环而不是 if() 块,因此,您的设计很可能是不正确的:)
根据 Brian Goetz 的伟大论文 https://www.ibm.com/developerworks/java/library/j-jtp06197/ “您只能在有限的情况下使用 volatile 变量而不是锁。以下两个标准都必须满足 volatile 变量以提供所需的线程安全性:
基本上,这些条件表明可以写入 volatile 变量的有效值集独立于任何其他程序状态,包括变量的当前状态。”因此它必须与锁同步。它不是线程安全的,因为是。