我将通过Java线程书。我发现了这个陈述
声明1: - “volatile变量只能安全地用于单个加载或存储操作,不能 适用于长或双变量。这些限制使得volatile变量的使用不常见“
我没有得到单个加载或存储操作的含义?为什么挥发不可能 应用于长或双变量?
声明2: - “易失性整数不能与++运算符一起使用,因为++运算符包含 多个指令.AtomicInteger类有一个方法,允许它保持的整数 原子地递增。“
为什么易失整数不能与++运算符一起使用以及AtomicInteger如何解决它?
答案 0 :(得分:5)
声明1: - “volatile变量只能安全地用于单次加载或存储操作,不能应用于long或double变量。这些限制使得volatile变量的使用不常见”
什么?我认为这完全是错误的。也许你的书已经过时了。
声明2: - “挥发性整数不能与++运算符一起使用,因为++运算符包含多个指令.AtomicInteger类有一个方法允许它保持的整数以原子方式递增。”
究竟是什么意思。 ++运算符实际上转换为像这样的机器代码(在类似Java的伪代码中):
sync_CPU_caches();
int processorRegister = variable;
processorRegister = processorRegister + 1;
variable = processorRegister;
sync_CPU_caches();
这不是线程安全的,因为即使它有内存屏障,并以原子方式读取,并以原子方式写入,也不能保证您不会在中间获得线程切换,并且处理器寄存器是本地的CPU核心(将它们视为CPU核心内部的“局部变量”)。但是AtomicInteger
是线程安全的 - 它可能是使用特殊的机器代码指令实现的,比如比较和交换。
答案 1 :(得分:0)
volatile变量的主要目的不是为了立即对该变量进行线程安全访问,而是为了确保在安全之前发生所谓的。
理论上是对
的呼唤volatile int i = 0;
和
int i = 0;
没有区别,因为无论如何都是原子地写入32位字(在32位和更高的机器上是正确的)。由于指针在内部也是32/64位整数,因此基本上只有一个volatile以原子方式进行操作,即如果在32位环境中使用64位长。
发生之前然而实际上是弄乱了上面的例子。要理解这一点,您需要知道线程不使用相关变量的实际内存,但可能会复制它以加快执行速度并可以重新排序语句以进行优化。现在,如果你有类似的东西:
Thread A: value = 1; doIt = true;
Thread B: if (doIt) { doDoIt(value); }
在线程B doIt
中可能是真的,但value
还不是1,因为JVM或新的value
可能已经更改了执行顺序尚未播放线程B value
的副本。
如果doIt
被声明为volatile,那么在访问它时,JVM会确保之前的所有代码已经被执行并被广播。所以上面的例子是使用volatile的实际原因。