volatile如何使我的类线程安全?

时间:2016-02-11 13:00:30

标签: java concurrency

我有一个班级

public class X {
    private volatile int value;

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }
}

它是否是线程安全的?即使我添加volatile关键字,我认为它也不是线程安全的。

2 个答案:

答案 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个属性解决它:

  • 写入易失性值后,它不仅会存储在CPU缓存中,而且会立即刷新到共享RAM中
  • 读取易失性值将始终从内存中读取,而不是从CPU缓存读取。

答案 1 :(得分:0)

简单地回答你的问题:当多个线程访问变量并且你不想/需要锁定它时,你应该使用volatile。从您提供的示例get可能会出现“线程安全”问题。 (见erosb的答案)

额外的:volatile的使用是有限的所以我强烈建议你使用AtomicInteger,它提供原子性和波动性(AtomicInteger类将其值字段存储在volatile变量中)。