<分区>
我正在尝试学习 Java 中多线程中使用的术语。因此,如果我在以下文本中使用了错误的定义,请纠正我:
我从不同资源中得到的发现
原子操作: 根据 Java 文档:
In programming, an atomic action is one that effectively happens all at once. An atomic action cannot stop in the middle: it either happens completely, or it doesn't happen at all. No side effects of an atomic action are visible until the action is complete.
这就是为什么读取或写入 long 或 double 变量不是原子的。因为它涉及两个操作,第一个 32 位和第二个 32 位读/写变量。另外,从上面的段落中,我了解到如果我在一个方法上使用 synchronized
,它会使该方法成为原子的(理论上来说)。
Volatile 变量: 同样来自 Java Doc:
This means that changes to a volatile variable are always visible to other threads. What's more, it also means that when a thread reads a volatile variable, it sees not just the latest change to the volatile, but also the side effects of the code that led up the change.
现在,同样根据 Joshua Bloch 的 Effective Java 2nd Edition,考虑书中关于 volatile
声明的以下几点:
考虑以下几点:
// Broken - requires synchronization!
private static volatile int nextSerialNumber = 0;
public static int generateSerialNumber() {
return nextSerialNumber++;
}
The method’s state consists of a single atomically accessible field, nextSerialNumber, and all possible values of this field are legal. Therefore, no synchronization is necessary to protect its invariants. Still, the method won’t work properly without synchronization.
这是因为 nextSerialNumber++
不是原子的,因为它执行读取、递增、写入。
我的总结
所以如果 nextSerialNumber++
不是原子的,并且需要 synchronize
。那为什么下面是原子的,不需要同步呢?
private static volatile long someNumber = 0;
public static int setNumber(long someNumber) {
return this.someNumber = someNumber;
}
我不明白的是为什么在 double
或 long
上使用 volatile 使其成为原子?
因为 volatile
所做的就是确保线程 B 是否尝试读取由线程 A 写入的 long
变量,并且只有它的 32 位由线程 A 写入,然后当线程 B 访问该资源时,它将获得线程 A 写入的 32 位数字。这并没有使其成为 atomic 作为术语的定义atomic 在 Java Doc 中有解释。