2009-09-23 31 views
92

set方法AtomicInteger之間有什麼區別? documentation沒有什麼可說的lazySetAtomicInteger懶惰設置與設置

最終設置爲給定值。

看來,儲值不會立即設置爲所需的值,而是將被安排在將來設定一段時間。但是,這種方法的實際用途是什麼?任何示例?

回答

95

Bug 6275329直引:

由於可能是最後一點JSR166隨訪野馬, 我們增加了一個 「lazySet」 方法對原子類 (的AtomicInteger,的AtomicReference等等)。這是一種利用 方法,在使用 非阻塞數據結構對代碼進行微調時,此方法有時很有用。語義是 ,寫入保證不會被任何 先前的寫入重新排序,但可能會被後續操作 (或等同地,可能對其他線程不可見)重新排序,直到 其他一些易失性寫入或同步操作發生)。

主要使用案例是爲了避免 長期垃圾保留而將非阻塞數據結構中的節點字段清零。它在無害時適用 如果其他線程在一段時間內看到非空值,但你想 這樣確保結構最終是GCable。在這種情況下,您可以通過避免零揮發寫的成本來獲得更好的性能。對於基於非參考的 原子,沿着這些線還有一些其他用例,因此該方法在所有的AtomicX類中都得到支持。

對於誰喜歡在共同的多處理器 機器級的障礙來考慮這些操作的人,lazySet 提供前述店店屏障(這是可以 無操作或在當前平臺很便宜) ,但沒有 存儲負載屏障(這通常是易失性寫入的昂貴部分 )。

+4

難道有人會爲我們其他人瞎折騰嗎? :( – Gaurav 2010-04-20 05:45:40

+9

懶惰是非易失性版本(例如,狀態更改不保證對所有具有'Atomic *'範圍的線程都可見)。 – yawn 2010-05-26 11:19:22

+45

我不明白爲什麼javadoc對它很差 – 2011-04-27 00:06:52

2

回覆:嘗試啞下來 -

你可以認爲這是一個方式來對待揮發性場,如果它是不揮發物爲特定的存儲設備(例如:REF = NULL;)操作。

這並不完全準確,但它應該足以讓您在「好吧,我真的不在乎」和「嗯,讓我考慮一下」之間做出決定。

3

這是我的理解,如果我錯了,請糾正我的錯誤: 您可以將lazySet()視爲「semi」volatile:它基本上是一個非易失性變量,用於由其他線程讀取,即由lazySet可能對其他線程不可見。但是當另一個寫操作發生時它變得不穩定(可能來自其他線程)。 我可以想象的lazySet的唯一影響是compareAndGet。因此,如果使用lazySet(),則來自其他線程的get()仍可能獲得舊值,但compareAndGet()將始終具有新值,因爲它是寫入操作。

+0

你不是指'compareAndSet'嗎? – 2017-02-03 10:50:48

8

的起源和lazySet的效用和潛在putOrdered可以在這裏找到的更廣泛的討論:http://psy-lob-saw.blogspot.co.uk/2012/12/atomiclazyset-is-performance-win-for.html

總結:lazySet是意義上的薄弱性寫它作爲一個店店,而不是一個商店裝載圍欄。這歸結爲lazySet被JIT編譯成一個MOV指令,該指令不能由編譯器重新排序,而不是用於易失性集合的非常昂貴的指令。

在讀取值時,您總是最終做一個易失性讀取(無論如何都使用Atomic * .get())。

lazySet爲單個寫入者提供了一致的易失性寫入機制,即對於單個寫入者使用lazySet增加計數器是完全合法的,多個線程遞增相同計數器將不得不使用CAS來解決競爭寫入,在Atomic *的incAndGet封面下發生了什麼。

+0

究竟是什麼,爲什麼我們不能說這是一個簡單的'StoreStore'障礙,而不是* StoreLoad? – Eugene 2017-07-18 09:04:04

11

lazySet可以用於rmw的線程間通信,因爲xchg是原子的,至於可見性,當writer線程進程修改一個cache線的位置時,reader線程的處理器會在下次讀取時看到它,因爲cache的一致性協議英特爾CPU將保證LazySet的工作,但高速緩存行將在下次讀取時更新,同樣,CPU必須足夠現代。對於Nehalem是一個多處理器平臺,處理器能夠「窺探」(竊聽)其他處理器對系統內存和其內部緩存的訪問的地址總線。他們使用這種監聽功能來保持其內部緩存與系統內存和其他互連處理器中的緩存保持一致。 如果通過監聽一個處理器檢測到另一個處理器打算寫入當前已緩存在共享狀態的內存位置,則監聽處理器將使其緩存塊無效,迫使其在下次訪問相同內存時執行緩存行填充位置。

預言熱點JDK用於x86 CPU建築 - >

lazySet == unsafe.putOrderedLong == XCHG RW(ASM指令作爲軟屏障成本上nehelem Intel的CPU 20個循環)

在x86 (x86_64)這樣的屏障比易失性或者AtomicLong getAndAdd更加便宜。在一個生產者中,一個消費者隊列場景中,xchg軟屏障可以強制lazySet(sequence + 1)之前的代碼行爲生產者線程在任何將使用(處理)新數據的消費者線程代碼之前發生課程消費者線程需要使用compareAndSet(sequence,sequence + 1)原子地檢查生產者序列是否增加了一個。

我後熱點源代碼跟蹤找lazySet的CPP的代碼的精確映射: http://hg.openjdk.java.net/jdk7/jdk7/hotspot/file/9b0ca45cd756/src/share/vm/prims/unsafe.cpp Unsafe_setOrderedLong - > SET_FIELD_VOLATILE定義 - > OrderAccess:release_store_fence。 對於x86_64,OrderAccess:release_store_fence被定義爲使用xchg指令。

你可以看到它是如何準確地在JDK7定義(Doug Lea的正在開發一些新的工具和JDK 8): http://hg.openjdk.java.net/jdk7/jdk7/hotspot/file/4fc084dac61e/src/os_cpu/linux_x86/vm/orderAccess_linux_x86.inline.hpp

,你也可以使用HDIS拆卸lazySet代碼的組件行動。

還有一個相關的問題: Do we need mfence when using xchg

+3

很難理解你在這裏得到什麼。你能否澄清你的觀點? – 2013-01-28 02:48:36

+3

「lazySet == unsafe.putOrderedLong == xchg rw(在nehelem intel cpu上充當軟屏障花費20個週期的asm指令) 這樣的屏障在性能上比x86(x86_64)要便宜得多,AtomicLong getAndAdd 「 - >這是不正確的,據我所知。 lazySet/putOrdered是一個MOV地址,這就是爲什麼JMM食譜將它描述爲x86上的禁用操作。 – 2014-07-29 13:43:43

6

Concurrent-atomic package summary

lazySet具有寫入(分配)volatile變量除了它允許與重新排序的記憶效應隨後的(但不是以前)內存操作本身並不會對普通的非易失性寫入施加重新排序約束。在其他使用上下文中,爲了垃圾回收,lazySet可以在爲空時返回一個再也不會被訪問的引用。

如果你是好奇lazySet那麼你欠自己其他的解釋太

的訪問效果和原子能的更新通常 遵循揮發的規則,作爲Java™的部分17.4中規定的記憶 語言規範。

得到具有讀取易失變量的記憶效應。

集合具有寫入(分配)易失性變量的記憶效應。

lazySet具有寫入(分配)volatile變量除了它允許使用本身不徵收重排與普通非易失性寫入 限制後續(但不是以前的)內存的動作重新排序的記憶效應。在其他用法 上下文中,lazySet可以在爲了垃圾收集而將空值清除時應用從未再次訪問的引用。

weakCompareAndSet自動讀取和有條件地寫入變量,但不會產生任何的之前發生的排序,所以提供 沒有關於擔保以前或以後的讀取和寫入速度比weakCompareAndSet的目標以外的任何變量 。 compareAndSet和所有其他讀取和更新操作(如getAndIncrement)都具有讀取和寫入易失性變量的記憶效應。