簡體   English   中英

java.util.concurrent.atomic.LongAdder class 的可行性

[英]Feasibility of java.util.concurrent.atomic.LongAdder class

LongAdder是一個巧妙設計的原子計數器,它應該在更新共享計數器時減少緩存行爭用。 問題是,它依賴於原子 CAS 操作來實際更新計數(這是它與更通用的LongAccumulator和朋友共享的特征)。

在 amd64 平台上(可能還有其他地方),原子 CAS 比原子 ADD 慢得多,至少在涉及中等數量的核心時是這樣。 因此,看起來,在單個共享VarHandle上簡單地進行原子加法是一個更好的主意:代碼更簡單,而在通用(大約 8 核)容器上性能並不差甚至更好。

VarHandle介導的原子添加相比,使用LongAdder有什么好處嗎?

對於更多的上下文:

  1. By default, Java does all atomic operations (even simple arithmetics) as CAS loops (for example: https://github.com/openjdk/jdk/blob/64644a10725abb4bea8a947508999be6c67c52ed/src/java.base/share/classes/jdk/internal/雜項/Unsafe.java#L2468 )。 如果願意,JIT 可以自由地將內在函數升級到更好的東西。
  2. LongAdder是一個分片的 CAS 循環,即使在低競爭級別下,它也絕對比任何簡單的 CAS 循環都快。
  3. 然而,對於任何爭用級別,“每個 CPU 一個 CAS 分片”場景( LongAdder默認)似乎比 AMD64 上的實際硬件原子加法(“LOCK XADD”指令)要慢一些。 通過大幅增加分片的數量(至少 2 倍的 CPU 數量,在大倍數上可以實現額外的收益,例如 8 倍及以上),它可以變得更快。
  4. 盡管如此,適當的原子計數器(進行硬件添加而不是 CAS 的)的簡單分片仍然會更快更簡單。

AtomicLong相比, LongAdder旨在在寫入繁重的場景中更好地擴展,在任何級別的爭用中,除了沒有,而且確實如此。

如果您的方案不是大量寫入,那么AtomicLong會更快。

C2 編譯器總是用硬編碼的程序集替換@HotSpotIntrinsicCandidate -annotated 方法,不僅是在感覺這樣做的時候。

lock xadd比 CAS 重試循環更快地增加一個值。 LongAdderlock xadd快,因為它在線程之間拆分計數器。 它創建了多個計數器,因此減少了爭用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM