2010-04-05 37 views
41

java內存模型規定編寫一個int是原子的:也就是說,如果您在一個線程中爲其寫入一個值(由4個字節組成)並在另一個線程中讀取它,您將得到所有字節或無,但從來沒有2個新的字節和2箇舊的字節等。在64位虛擬機上編寫參考原子

這不保證long。在此,將0x1122334455667788寫入一個變量,該變量保存0之前可能會導致另一個線程讀取0x1122334400000000x0000000055667788

現在規範沒有強制對象引用是int或long-sized。出於類型安全原因,我懷疑它們是以原子方式寫入的,但在64位VM上,這些引用可能是64位值(僅限於內存地址)。

現在,這裏是我的問題:

  • 是否有覆蓋這個(我還沒有發現)任何存儲器模型規範?
  • 是否長篇可疑是64位VM上的原子?
  • 虛擬機是否被迫將引用映射到32位?

問候, 斯特芬

+2

@Steffen萬歲:吹毛求疵,但請注意,並非所有的引用都是內部64位甚至64位虛擬機(由於垃圾64所定義產生數量驚人)。現代VM正在使用名爲*「CompressedOops」*的指針壓縮/引用壓縮:http://wikis.sun.com/display/HotSpotInternals/CompressedOops因此,我並不反對它們*可能是64位值,但它們通常不是(並不是說這與德克公佈的答案有很大關係)。 – SyntaxT3rr0r 2010-04-05 02:21:16

回答

52

參見JLS section 17.7: Non-atomic Treatment of double and long

對於Java編程語言存儲器模型的目的,對非易失性長或雙值的 單個寫入視爲兩個 單獨寫入:每個32位一半。這可能會導致 的情況,其中一個線程看到一個寫入的64位值的前32位,另一個寫入來自第二個32位。

對volatile和double值的寫入和讀取總是原子的。

無論是否將它們實現爲32位或64位值,無論是否使用 ,寫入和讀取引用始終都是原子。

一些實施方案可發現可以方便地在相鄰的 32位值上的64位長或雙值的單個寫 動作分成兩個寫入動作。爲了提高效率,這種行爲是 實現特定的; Java虛擬機 的實現可以自由地執行寫入長和雙值的原子方式或在 兩部分。

鼓勵實施Java虛擬機,以避免 在可能的情況下分割64位值。鼓勵程序員 將共享64位值聲明爲volatile或正確同步其程序 以避免可能的複雜情況。

(強調)

+0

好的,我又錯過了規格中的要點。對我來說,我太累了,應該睡覺而不是問問題......感謝指針。 (AGAIN) – 2010-04-05 01:41:50

+1

如果「寫入和讀取引用始終是原子的,無論它們是以32位還是64位值實現的」,爲什麼我們需要AtomicReference類(https://docs.oracle.com/javase/) 7 /文檔/ API/JAVA/util的/並行/原子/ AtomicReference.html)? 僅因爲方法getAndSet/compareAndSet? – 2016-10-03 22:10:08

+0

沒有看到殘缺的參考值只是圖片的一部分。 'AtomicReference'主要用於它的同步API(你提到的'compareAndSet'),@ mc.android.developer,這裏沒有「only」。這實際上是重要的一部分。 – Dirk 2016-10-04 08:57:34