AtomicInteger

今天寫代碼,嘗試使用了AtomicInteger這個類,感受使用起來很爽,特別適用於高併發訪問,下面貼一個簡單的例子:java

Java代碼   收藏代碼
  1. CashierContext類部分代碼:  
  2.   
  3. private Map<String, AtomicInteger> counter          = new HashMap<String, AtomicInteger>();  
  4.   
  5.   
  6. private void initCounter() {  
  7.      counter.put("cvm", new AtomicInteger(0));  
  8. }  
  9.   
  10. //被調用一次自動+1  
  11.   
  12. public MobileCashierViewModel getCvm() {  
  13.   
  14.         if (cvm != null) {  
  15.             counter.get("cvm").incrementAndGet();  
  16.         }  
  17.         return cvm;  
  18.     }  
 

使用場景:面試

由於經過WS服務獲取MobileCashierViewModel 這個對象比較頻繁,會很影響系統資源,能夠將cvm存入緩存中,想要查看緩存cvm有多大價值,那麼能夠設置一個計數,來統記cvm被調用的次數算法

 

 

而後將CashierContext放入ThreadLocal中,而後再寫一個過濾器,在過濾器裏面能夠獲得獲取這個服務從緩存中取的次數,這個就能夠很容易看出來緩存價值。mongodb

 

那麼爲何不使用記數器自加呢,例如count++這樣的,由於這種計數是線程不安全的,高併發訪問時統計會有誤,而AtomicInteger爲何可以達到多而不亂,處理高併發應付自如呢,咱們纔看看AtomicInteger的源代碼:編程

 

 

Java代碼   收藏代碼
  1. private volatile int value;  
 

 

你們能夠看到有這個變量,value就是你設置的自加起始值。注意看它的訪問控制符,是volatile,這個就是保證AtomicInteger線程安全的根源,熟悉併發的同窗必定知道在java中處理併發主要有兩種方式:swift

1,synchronized關鍵字,這個你們應當都各類面試和筆試中常常遇到。緩存

2,volatile修飾符的使用,相信這個修飾符你們平時在項目中使用的也不是不少。安全

 

這裏重點說一下volatile:cookie

Volatile修飾的成員變量在每次被線程訪問時,都強迫從共享內存從新讀取該成員的值,並且,當成員變量值發生變化時,強迫將變化的值從新寫入共享內存,這樣兩個不一樣的線程在訪問同一個共享變量的值時,始終看到的是同一個值。session

 

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

 

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

 

建議:當多個線程同時訪問一個共享變量時,能夠使用volatile,而當訪問的變量已在synchronized代碼塊中時,沒必要使用。

缺點:使用volatile將使得VM優化失去做用,致使效率較低,因此要在必要的時候使用。

 

 

分享到:   
參考知識庫
人工智能知識庫3342  關注 | 409  收錄
MongoDB知識庫5177  關注 | 303  收錄
Hbase知識庫6169  關注 | 63  收錄
區塊鏈知識庫3013  關注 | 105  收錄
評論
7 樓  dxqrr 2015-03-06  
確實不是由於volatile 關鍵字的緣由
6 樓  紫藤蘿 2014-08-13  
ydm305365 寫道
看這篇文章的同仁,請不要被本文的做者誤導,使用volatile關鍵字,並不能保證i++,操做的原子性,volatile解決的只是多線程間共享變量的可見性問題,本身能夠隨便寫個用volatile修飾的變量,而後用多線程多跑i++,這種方法,很容易發現問題所在。

最近在看多線程併發的問題,想知道這個volatile應用場景,麻煩解說下。
5 樓  ydm305365 2014-06-08  
AtomicInteger之因此可以實現原子遞增,並非由於使用了volatile關鍵字,而是由於unsafe,真正核心的方法,請查看源碼

Java代碼   收藏代碼
  1. public final int incrementAndGet() {    
  2.     for (;;) {    
  3.         //這裏能夠拿到value的最新值    
  4.         int current = get();    
  5.         int next = current + 1;    
  6.         if (compareAndSet(current, next))    
  7.             return next;    
  8.     }    
  9. }   

compareAndSet主要在這個方法上,這個方法主要經過CAS算法,具體什麼能夠
能夠查看這篇文章
http://caogen81.iteye.com/blog/2002884
4 樓  ydm305365 2014-06-08  
看這篇文章的同仁,請不要被本文的做者誤導,使用volatile關鍵字,並不能保證i++,操做的原子性,volatile解決的只是多線程間共享變量的可見性問題,本身能夠隨便寫個用volatile修飾的變量,而後用多線程多跑i++,這種方法,很容易發現問題所在。
3 樓  cha_bill 2013-10-22  
你這個類不是線程安全的類,雖然你用了AtomicInteger,你這段代碼只能保證map中的Integer是線程安全的,可是你使用了,HashMap,這個類不是線程安全的,因此你這個類,從你貼上的代碼來看,不是線程安全的。
2 樓  greenwen 2013-09-13  
jsbanh0 寫道
有個問題,Atomic類型的變量爲什麼是線程安全的緣由是由於 使用volatile修飾。
根據樓主的判斷,那麼下述代碼中的兩個變量會是相同的結果,但實際運行並不是如此,詳見
http://raychase.iteye.com/blog/1679131一文,那這不是互相矛盾的麼,仍是我理解錯了呢
Java代碼   收藏代碼
  1. private static volatile int nonAtomicCounter = 0;  
  2. private static volatile AtomicInteger atomicCounter = new AtomicInteger(0);  
  3.   
  4. nonAtomicCounter++;  
  5. atomicCounter.incrementAndGet();  
  

Java代碼   收藏代碼
  1. nonAtomicCounter++ 先判斷值 再自增  
  2. ++nonAtomicCounter是先自增再判斷值  
  3. 這兩個的結果是不一樣的  
  4.   
  5. ++nonAtomicCounter  
  6. atomicCounter.incrementAndGet()  
  7. 這兩個結果才相同  
1 樓  jsbanh0 2012-09-18  
有個問題,Atomic類型的變量爲什麼是線程安全的緣由是由於 使用volatile修飾。
根據樓主的判斷,那麼下述代碼中的兩個變量會是相同的結果,但實際運行並不是如此,詳見
http://raychase.iteye.com/blog/1679131一文,那這不是互相矛盾的麼,仍是我理解錯了呢
Java代碼   收藏代碼
  1. private static volatile int nonAtomicCounter = 0;  
  2. private static volatile AtomicInteger atomicCounter = new AtomicInteger(0);  
  3.   
  4. nonAtomicCounter++;  
  5. atomicCounter.incrementAndGet();  
相關文章
相關標籤/搜索