簡體   English   中英

這個增量和獲取線程安全嗎? 看來是從eh快取中拉出物件

[英]Is this incrementAndGet thread-safe? It seems to pull object from eh cache

這個servlet似乎是從ehCache中從具有此對象的Element中獲取一個對象: http : //code.google.com/p/adwhirl/source/browse/src/obj/HitObject.java? repo=servers-mobile

然后繼續增加一個原子長的計數器:

http://code.google.com/p/adwhirl/source/browse/src/servlet/MetricsServlet.java?repo=servers-mobile#174

    //Atomically record the hit
    if(i_hitType == AdWhirlUtil.HITTYPE.IMPRESSION.ordinal()) {
        ho.impressions.incrementAndGet();
    }
    else {
        ho.clicks.incrementAndGet();
    }

這對我來說似乎不是線程安全的,因為可能會從緩存中獲取多個線程,如果兩個線程同時增加,則可能會失去點擊/展示次數。

您是否同意這不是線程安全的?

AtomicLongAtomicInteger在內部使用AtomicLong比較和設置(或比較和交換)。 這個想法是您告訴CAS兩件事:您期望long / int擁有的值,以及您想要將其更新為的值。 如果long / int具有您說的應有的值,則CAS將自動進行更新並返回true ;否則,返回true 否則,它將不會進行更新,並且將返回false 許多現代芯片在機器代碼級別非常有效地支持CAS。 如果JVM在沒有CAS的環境中運行,則可以使用互斥體(Java稱為同步)來實現CAS。 無論如何,一旦有了CAS,就可以通過以下邏輯(以偽代碼)安全地實現原子增量:

long incrementAndGet(atomicLong, byIncrement)
    do
        oldValue = atomicLong.get()            // 1
        newValue = oldValue + byIncrement
    while ! atomicLong.cas(oldValue, newValue) // 2
    return newValue

如果另一個線程進入並在// 1// 2行之間進行自己的遞增,則CAS將失敗,並且循環將再次嘗試。 否則,CAS將成功。

這種方法有一個賭注:如果爭用較低,則CAS的速度要比同步塊快,這不太可能導致線程上下文切換。 但是,如果存在很多爭用,則某些線程將不得不以每個增量進行多次循環迭代,這顯然會浪費工作。 一般來說,在大多數常見負載下,incrementAndGet將更快。

增量是線程安全的,因為AtomicInteger和Family保證了這一點。 但是從緩存中插入和提取存在一個問題,其中可以創建和插入兩個(或更多)HitObject。 這可能會導致在首次訪問此HitObject時丟失某些匹配。 正如@ denis.solonenko指出的那樣,代碼中已經有一個TODO可以解決此問題。

但是,我想指出的是,此代碼僅在首次訪問給定的HitObject時並發。 一旦將HitObject保存在緩存中(並且不再有創建或插入HitObject的線程),那么此代碼就完全是線程安全的。 因此,這只是一個非常有限的並發問題,這可能就是他們尚未解決此問題的原因。

暫無
暫無

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

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