Java规范保证基本变量赋值始终是原子的(除了long
和double
类型)。
相反,Fetch-and-Add操作对应于著名的i++
自增操作,将是非原子的,因为它导致读取-修改-写入操作。
假设这段代码:
public void assign(int b) {
int a = b;
}
生成的字节码是:
public void assign(int);
Code:
0: iload_1
1: istore_2
2: return
因此,我们可以看到这个任务由两个步骤(加载和存储)组成。
假设有以下代码:
public void assign(int b) {
int i = b++;
}
字节码:
public void assign(int);
Code:
0: iload_1
1: iinc 1, 1 //extra step here regarding the previous sample
4: istore_2
5: return
了解到X86处理器(至少是现代处理器)可以原子性地执行增量操作,如下所述:
在计算机科学中,fetch-and-add CPU指令是一种特殊指令,可以原子性地修改内存位置的内容。它用于在多处理器系统中实现互斥和并发算法,这是信号量的一般化。
因此,第一个问题:尽管字节码需要两个步骤(加载和存储),但Java是否依赖于分配操作始终是以原子方式执行的事实,并且因此可以确保其规范中的原子永久性(对于原始分配)?
第二个问题:确认使用非常现代的X86处理器并且没有在不同架构之间共享编译代码时,根本不需要同步i ++操作(或AtomicInteger
)吗?考虑它已经是原子的。
a = b
中,可能会读取b
,然后将其变异为新值,然后将原始值分配给a
。但是,原子性保证了a
不会成为b
所持有的2个值的混合体。 - assylias