Java 顺序一致性和原子性之间有什么区别?
我读到java volatile是顺序一致的,但不是原子的。 对于原子性,java提供了不同的库 有人能用简单的英语解释一下两者的区别吗Java 顺序一致性和原子性之间有什么区别?,java,c++,atomic,volatile,Java,C++,Atomic,Volatile,我读到java volatile是顺序一致的,但不是原子的。 对于原子性,java提供了不同的库 有人能用简单的英语解释一下两者的区别吗 (我相信问题的范围包括C/C++并因此添加这些语言标记以获得更多的受众。)假设您有以下两个变量: public int a = 0; public volatile int b = 0; synchronized (lock) { a = 1; b = 2; } ... synchronized (lock) { System.o
(我相信问题的范围包括C/C++并因此添加这些语言标记以获得更多的受众。)假设您有以下两个变量:
public int a = 0;
public volatile int b = 0;
synchronized (lock) {
a = 1;
b = 2;
}
...
synchronized (lock) {
System.out.println("a = " + a + "; b = " + b);
}
假设有一个线程可以
a = 1;
b = 2;
如果另一个线程读取这些值并看到b==2,那么它保证也会看到a==1
但是读取线程可以看到a==1
和b==0
,因为这两次写入不是原子操作的一部分,所以读取线程可能会在第一个线程为b
赋值之前看到对a
所做的更改
要使这两次写入原子化,您需要同步对这两个变量的访问:
public int a = 0;
public volatile int b = 0;
synchronized (lock) {
a = 1;
b = 2;
}
...
synchronized (lock) {
System.out.println("a = " + a + "; b = " + b);
}
在这种情况下,读取线程将看到
a==0
和b==0
,或a==1
和b==2
,但不会看到中间状态。想象一下类中的这两个变量:
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
):
您不能保证v将增加2。这是因为v++
实际上是三条语句:
load v;
increment v;
store v;
由于线程交错,v只能增加一次(两个线程将加载相同的值)。+1,但你并不是说“这是顺序一致性”和“这是原子性”。是的,我认为这是显而易见的。但assylias的答案比我的答案更清楚,也更好。我不认为
volatile
在C/C++中提供了与Java相同的保证。特别是,我不认为它在C中提供了你所说的顺序一致性(即内存界限适用于其他变量)——TBC。@assylias我不是说volatile在C/C++中有相同的含义。我相信不会的。我指的是c/c++和Java之间常见的“顺序一致性和原子性”概念。在C/C++中,volatile关键字停止变量使用的优化,不用于维护在使用volatile变量进行操作之前指定的操作之间的顺序一致性。如果您可以添加一个示例来演示原子和顺序的内容,这将是完整的答案。我们可以不使用互斥锁就这样做吗?现在无法更新,但是可以,所以cslled无锁算法使用CAS操作来提供原子性。java中的所有AtomicXXX类都使用它。