将以下陈述分开是正确的:
int v = ++j;
为:
答案 0 :(得分:8)
是的,int
(或更小的数据类型)读/写/算术运算是原子的。无论是32位还是64位,引用(读/写)也都是原子的。
但是,对64位long
和double
的操作可能不是原子操作。
double
and long
某些实现可能会发现将64位
long
或double
值上的单个写操作划分为相邻32位值的两个写操作很方便。为了效率,这种行为是特定于实现的; Java虚拟机可以原子地或分两部分对long
和double
值进行写入。出于Java编程语言内存模型的目的,对非
volatile
long
或double
值的单个写入被视为两个单独的写入:每个写入一个32-一点半。这可能导致线程从一次写入看到64位值的前32位,而从另一次写入看到第二次32位的情况。volatile long
和double
值的写入和读取始终是原子的。对引用的写入和读取始终是原子的,无论它们是实现为32位还是64位值。鼓励VM实现者尽可能避免拆分64位值。建议程序员将共享的64位值声明为
volatile
或正确同步其程序以避免可能的复杂情况。
请注意,前置或后置递增/递减运算符本身都不是原子的,甚至不在int
或byte
上:读/写/算术运算在明显不同的步骤中发生。
答案 1 :(得分:1)
关闭。第2步是原子的。在这种情况下,j
必须是byte
,char
,short
或int
中的一个,并且每个都可以加载并以原子方式存储。
一旦将值加载到硬件寄存器中,其他线程就不可能干扰它。在JLS中可能存在关于原始操作的原子性的东西......但我无法发现它。
答案 2 :(得分:1)
是的,你的假设是正确的。增加一个int导致三个步骤(因此它不是原子的),分配它是另一个步骤。这是结果字节码:
..
istore_1
iinc 1, 1
iload_1
istore_2
..
答案 3 :(得分:0)
我会使用AtomicInteger
AtomicInteger j; // do init
int v = j.incrementAndGet();
JAD的快速视图显示了以下字节代码:
int j = 0;
// 0 0:iconst_0
// 1 1:istore_1
int v = ++j;
// 2 2:iinc 1 1
// 3 5:iload_1
// 4 6:istore_2