我有一个班级
public class X {
private volatile int value;
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
它是否是线程安全的?即使我添加volatile
关键字,我认为它也不是线程安全的。
答案 0 :(得分:2)
线程安全性可以表示为“如果类的对象在多线程环境中的行为与在单线程环境中完全相同,那么它是线程安全的”,或者可能改为“行为与”完全相同“我们可以说“行为正确”。
在您的情况下,正确的行为意味着在致电setValue(N)
后,以下getValue()
会返回N
。如果你不使用volatile
修饰符,只有在单线程环境中才会这样:如果你在Thread1上调用setValue(N)
然后在Thread2上调用getValue()
之后,那么它不一定会返回N
。问题是Thread1和Thread2可能在不同的CPU内核上执行,而CPU内核通常不直接读/写共享内存:两个处理器可以有单独的CPU缓存,setValue(N)
调用可能只修改值成员的CPU缓存副本,因此RAM的更改不会立即可见。此外,即使N
已在共享内存中可用,getValue()
也可能从第二个处理器缓存读取缓存但过时的值。因此,您在Thread1上执行的值更改可能无法在Thread2上立即显示,因此getValue()
可能会返回已弃用的值。
volatile修饰符使用以下2个属性解决它:
答案 1 :(得分:0)
简单地回答你的问题:当多个线程访问变量并且你不想/需要锁定它时,你应该使用volatile。从您提供的示例get
可能会出现“线程安全”问题。 (见erosb的答案)
额外的:volatile的使用是有限的所以我强烈建议你使用AtomicInteger,它提供原子性和波动性(AtomicInteger类将其值字段存储在volatile变量中)。