如果我有一个易失的布尔变量(我们称之为valid),下面这段Java代码是线程安全的吗?
或者,我需要同步吗?因为只有在valid为false时才设置为true(因此valid的设置取决于其当前值)?
if (valid)
return;
valid = true;
或者,我需要同步吗?因为只有在valid为false时才设置为true(因此valid的设置取决于其当前值)?
if (valid)
return;
valid = true;
这需要同步,因为如果一个线程在赋值之前将valid评估为false,然后暂停执行,然后另一个线程在将valid设置为true之前也检查valid为false,则会有两个线程从此处运行代码(这可能不是您想要的)。
它不是线程安全的。但如果这是整个代码,那就无关紧要。
AtomicBoolean
,它使用低级操作实现条件更新而无需同步。
该标志存在两个单独的(即非原子)访问,因此除非该线程是唯一执行标志写操作的线程,否则需要同步。即使如此,为了以防未来更改,最好也要进行同步。
你的代码不是线程安全的,但它是否安全取决于你的其他代码。
你需要确保在单个线程中只执行一次跟随valid = true
的代码吗?如果是这样,那么你的代码就不安全了,因为任意数量的线程都可以读取valid
的false
值,然后将其设置为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
变量,让每个线程只执行一次代码。
此外,在考虑同步和volatile时如果有疑问...就使用同步吧。通常这样更清晰,而且将获得从使用volatile
获得的所有东西,除了它可以更容易地理解代码如何工作。
线程安全是一个系统范围的属性。你不能孤立地看待一段代码并称其为线程安全/不安全。它取决于其他线程如何与它交互以及一致性要求是什么。话虽如此,大多数线程安全的设计都有while()循环而不是if()块,因此,你的设计很可能是不正确的:)