关于volatile和Atomic类的一些疑问?

时间:2013-11-30 16:32:18

标签: java multithreading volatile atomicity

我将通过Java线程书。我发现了这个陈述

声明1: - “volatile变量只能安全地用于单个加载或存储操作,不能 适用于长或双变量。这些限制使得volatile变量的使用不常见“

我没有得到单个加载或存储操作的含义?为什么挥发不可能 应用于长或双变量?

声明2: - “易失性整数不能与++运算符一起使用,因为++运算符包含 多个指令.AtomicInteger类有一个方法,允许它保持的整数 原子地递增。“

为什么易失整数不能与++运算符一起使用以及AtomicInteger如何解决它?

2 个答案:

答案 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的实际原因。