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