2017-07-26 39 views
1

下面的代码可以在多线程中工作吗? !boolean是java中的一个原子操作吗?!!boolean是java中的一个原子操作吗?

volatile boolean flag = true; 
if (!flag){ 
    do something 
} 
+1

即使是这样,一旦你进入if体内什么阻止它再次改变值呢?这与“not”期间的变化有何不同?为什么你的代码依赖于这是原子? – GManNickG

+1

这是一个原子读取(无论是否为volatile),但“做某事”与前面的检查无关,除非您同步它。 – shmosel

+0

为什么不使用AtomicBoolean对象? –

回答

1

!boolean在java中的一个[n]原子操作吗?

号有三个操作位置:

  1. 负载变量
  2. 比较和分支。
  3. '做点事情'。

线程切换可以发生在1和2之间,或者2和3之间,并且底层布尔值的值可以在任何时间或者在3或之后改变。

所以如果你想确定'做点什么'只发生如果flag同时错误,你将不得不同步,或使用信号量。

+2

这是最令人误解的。读取本身是原子的(与之相对,比如说,非易失性长文件)。加载和比较之间的变量可能会发生变化的事实没有意义。重要的是变量可以在读取之后随时改变*无需额外的同步。 – shmosel

+0

@shmosel'*没有*意义?'真? – EJP

+1

这是一个问题还是一个陈述?你是否有一个例子,其中的行为会有明显的差异,纯粹是因为加载和比较不是原子的? – shmosel

1

因为它标志着volatile和值是一种原始的,这样保证了读取将始终是一致(不读部分初始化值的可能性)。

即使没有标记为volatile,JVM也会始终以原子方式读取存储在32位或更小中的任何原始值。这是JLS 17.6中的语言要求。 (JLS 17.7允许对64位原始值进行“字符撕裂”,即longdouble,它说这种行为是特定于实现的。实际上,在我所知的所有生产64位JVM实现中,甚至可以读取64位值始终是原子的。)

反转布尔操作的操作可能不是原子读取,但如果是这样的话,它将通过将布尔值复制到JVM指令堆栈工作,所以仍然不存在数据的可能性腐败(因为将值推入操作数栈是一个原子操作)。更有可能的是,JIT只会将您的if条件反转并跳转到另一个分支,而不是实际反转布尔值。

当然,你仍然没有任何保证,在它被另一个线程改变之前,它不会立即读取该值,所以从字面上看,下一个指令可以开始执行,同时布尔值被另一个线程设置为true线。

+0

有一场竞赛,而且JVM不会以原子方式读取长整数或双整数。 – EJP

+1

'volatile'在这种情况下不能确保原子性。 – shmosel

+1

“原子性”和“种族”不一样吗? –