我对易变语义毫无疑问。
假设有三个线程T1,T2和T3,以及给定类的单个实例。
class Foo {
private int x = 1;
private int y = 2;
private int z = 3;
private volatile int w = 4;
private volatile int v = 5;
public void setX(int x) {
this.x = x;
}
public int getX() {
return this.x;
}
(...)
}
假设发生以下一系列读/写操作:
1. (T1) foo.getX(); // stored in a local memory of T1
2. (T1) foo.getY(); // stored in a local memory of T1
3. (T2) foo.setX(10);
4. (T2) foo.setY(20);
5. (T3) foo.getY(); // T3 may see 2 or 20, no guarantees if a write action from point 4 is visible to T3
6. (T3) foo.setZ(30);
7. (T3) foo.setW(40);
8. (T3) foo.setV(50);
9. (T1) foo.getW()
10. (T1) foo.getZ()
11. (T1) foo.getY()
12. (T1) foo.getX()
我知道可以保证在点9处的T1将在点7处看到一个值,并且可以保证在点10处的T1将在点6中看到一个值(至少与此保持一致)值)。
但是,这些陈述是正确的吗?
请确认我的理解是正确的。
答案 0 :(得分:1)
只要您的获取/设置操作仅获取和设置变量,那么所有假设都是正确的。
在Java中,变量存储在内存中。但是编译器(和运行时)将允许将变量临时存储在CPU高速缓存中,以便在算法或代码段期间可以更快地进行读写。
这种缓存的缺点是当Core完成变量时,它将把它写回内存,就好像它只被更新过一次一样。使用其他变量时,其他核心无法看到其状态。更糟糕的是,无法保证何时将其写回到内存。
通过将变量设置为Volatile,您告诉Java不允许将该变量放入ANY缓存。对变量的读或写必须在内存中进行。
这意味着Volatile将对原子变量进行单个操作。但是,这也会使对变量的长时间运算变得更慢。因此,volatile并不是提高多线程代码性能的解决方案。
值得注意的是,需要多次读或写的操作是 not 原子的。例如,实际上为i = i + 1的i ++可以在写入完成之前更改i的值。
如果您需要保证操作是原子发生的,则可以使用锁或semtex(慢速),也可以使用诸如写入时复制(COW)之类的聪明范例来允许原子读取和原子写入。