9

我读到java volatile是顺序一致的,但不是原子的。对于原子性,java 提供了不同的库。

有人可以用简单的英语解释两者之间的区别吗?

(我相信问题范围包括 C/C++,因此添加了这些语言标签以吸引更多的受众。)

4

2 回答 2

8

想象一个类中的这两个变量:

int i = 0;
volatile int v = 0;

而这两种方法

void write() {
    i = 5;
    v = 2;
}

void read() {
    if (v == 2) { System.out.println(i); }
}

volatile 语义保证read将打印 5 或不打印(当然假设没有其他方法正在修改字段)。如果v不是易失性的,read还不如打印 0,因为i = 5并且v = 2可以重新排序。我想这就是您所说的顺序一致性,它具有更广泛的含义。

另一方面,volatile 不保证原子性。因此,如果两个线程同时调用此方法(v 相同volatile int):

void increment() {
    v++;
}

你不能保证 v 会增加 2。这是因为v++实际上是三个语句:

load v;
increment v;
store v;

并且由于线程交错 v 只能增加一次(两个线程将加载相同的值)。

于 2013-03-17T22:33:04.200 回答
6

假设你有这两个变量:

public int a = 0;
public volatile int b = 0;

假设有一个线程

a = 1;
b = 2;

如果另一个线程读取这些值并看到 b == 2,则保证也看到 a == 1。

但是读取线程可以看到a == 1and b == 0,因为两次写入不是原子操作的一部分,所以读取线程可能会a在第一个线程为 赋值之前看到对 的更改b

为了使这两个写入原子,您需要同步对这两个变量的访问:

synchronized (lock) {
    a = 1;
    b = 2;
}

...

synchronized (lock) {
    System.out.println("a = " + a + "; b = " + b);
}

在这种情况下,读取线程将看到a == 0and b == 0, or a == 1and b == 2,但永远不会看到中间状态。

于 2013-03-17T22:32:31.207 回答