天天看點

AtomicInteger

今天寫代碼,嘗試使用了AtomicInteger這個類,感覺使用起來很爽,特别适用于高并發通路,下面貼一個簡單的例子:

AtomicInteger

CashierContext類部分代碼:  

private Map<String, AtomicInteger> counter          = new HashMap<String, AtomicInteger>();  

private void initCounter() {  

     counter.put("cvm", new AtomicInteger(0));  

}  

//被調用一次自動+1  

public MobileCashierViewModel getCvm() {  

        if (cvm != null) {  

            counter.get("cvm").incrementAndGet();  

        }  

        return cvm;  

    }  

使用場景:

因為通過WS服務擷取MobileCashierViewModel 這個對象比較頻繁,會很影響系統資源,可以将cvm存入緩存中,想要檢視緩存cvm有多大價值,那麼可以設定一個計數,來統記cvm被調用的次數

然後将CashierContext放入ThreadLocal中,然後再寫一個過濾器,在過濾器裡面可以得到擷取這個服務從緩存中取的次數,這個就可以很容易看出來緩存價值。

那麼為什麼不使用記數器自加呢,例如count++這樣的,因為這種計數是線程不安全的,高并發通路時統計會有誤,而AtomicInteger為什麼能夠達到多而不亂,處理高并發應付自如呢,我們才看看AtomicInteger的源代碼:

AtomicInteger

private volatile int value;  

大家可以看到有這個變量,value就是你設定的自加起始值。注意看它的通路控制符,是volatile,這個就是保證AtomicInteger線程安全的根源,熟悉并發的同學一定知道在java中處理并發主要有兩種方式:

1,synchronized關鍵字,這個大家應當都各種面試和筆試中經常遇到。

2,volatile修飾符的使用,相信這個修飾符大家平時在項目中使用的也不是很多。

這裡重點說一下volatile:

Volatile修飾的成員變量在每次被線程通路時,都強迫從共享記憶體重新讀取該成員的值,而且,當成員變量值發生變化時,強迫将變化的值重新寫入共享記憶體,這樣兩個不同的線程在通路同一個共享變量的值時,始終看到的是同一個值。

java語言規範指出:為了擷取最佳的運作速度,允許線程保留共享變量的副本,當這個線程進入或者離開同步代碼塊時,才與共享成員變量進行比對,如果有變化再更新共享成員變量。這樣當多個線程同時通路一個共享變量時,可能會存在值不同步的現象。

而volatile這個值的作用就是告訴VM:對于這個成員變量不能儲存它的副本,要直接與共享成員變量互動。

建議:當多個線程同時通路一個共享變量時,可以使用volatile,而當通路的變量已在synchronized代碼塊中時,不必使用。

缺點:使用volatile将使得VM優化失去作用,導緻效率較低,是以要在必要的時候使用。

本文轉自農夫山泉别墅部落格園部落格,原文連結:http://www.cnblogs.com/yaowen/p/6110032.html,如需轉載請自行聯系原作者