2017-07-26 67 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

「原子性」和「種族」不一樣嗎? –