1. 程式人生 > >執行緒安全性---面試題--i++的執行緒安全性問題

執行緒安全性---面試題--i++的執行緒安全性問題

這個類真的非常實用,更重要的是 它確實非常簡單:

附上自己的程式碼,可以自己試試:

AtomicInteger,一個提供原子操作的Integer的類。在Java語言中,++i和i++操作並不是執行緒安全的,在使用的時候,不可避免的會用到synchronized關鍵字。而AtomicInteger則通過一種執行緒安全的加減操作介面。

程式碼:

package test;

import java.util.concurrent.atomic.AtomicInteger;
/**
 * 來看AtomicInteger提供的介面。

 //獲取當前的值
 
 public final int get()
 
 //取當前的值,並設定新的值
 
  public final int getAndSet(int newValue)
 
 //獲取當前的值,並自增
 
  public final int getAndIncrement() 
 
 //獲取當前的值,並自減
 
 public final int getAndDecrement()
 
 //獲取當前的值,並加上預期的值
 
 public final int getAndAdd(int delta)


 * @author YangBaoBao
 *
 */
public class AtomicIntegerDemo {
 public static void main(String[] args) {
  AtomicInteger ai=new AtomicInteger(0);
  int i1=ai.get();
  v(i1);
  int i2=ai.getAndSet(5);
  v(i2);
  int i3=ai.get();
  v(i3);
  int i4=ai.getAndIncrement();
  v(i4);
  v(ai.get());
  
 }
 static void v(int i)
 {
  System.out.println("i : "+i);
 }
}

那麼為什麼不使用記數器自加呢,例如count++這樣的,因為這種計數是執行緒不安全的,高併發訪問時統計會有誤,而AtomicInteger為什麼能夠達到多而不亂,處理高併發應付自如呢,我們才看看AtomicInteger的原始碼:

Java程式碼  收藏程式碼
  1. private volatile int value;  

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

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

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

這裡重點說一下volatile:

Volatile修飾的成員變數在每次被執行緒訪問時,都強迫從共享記憶體重新讀取該成員的值,而且,當成員變數值發生變化時,強迫將變化的值重新寫入共享記憶體,這樣兩個不同的執行緒在訪問同一個共享變數的值時,始終看到的是同一個值。

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

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

建議:當多個執行緒同時訪問一個共享變數時,可以使用volatile,而當訪問的變數已在synchronized程式碼塊中時,不必使用。

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