i++為什么是線程不安全的


如果是全局變量,i++是不安全的,因為java在操作i++的時候,是分步驟做的,可以理解為:
tp = i;
tp2 = i+1;
i=tp2;
如果線程1在執行第一條代碼的時候,線程2訪問i變量,這個時候,i的值還沒有變化,還是原來的值,所以是不安全的。

從更底層的角度講,主要是因為i++這個操作不是原子性的,這個會編譯成i= i +1; 所以會出現多線程訪問沖突問題。volatile雖然可以保證多線程對修改可見,但代碼中用到了
i++, 主要是i++不是原子性操作,這個會編譯成i = i +1,其實是做了3個步驟,一個是讀取,修改,寫入 。所以會出現多線程訪問沖突問題

解決方案:

在Java語言中,++i和i++操作並不是線程安全的,在使用的時候,不可避免的會用到synchronized關鍵字。而java.util.concurrent.AtomicInteger是一個提供原子操作的Integer類,其提供了線程安全且高效的原子操作,是線程安全的。

AtomicInteger類的底層實現原理是利用處理器的CAS操作(Compare And Swap,比較與交換,一種有名的無鎖算法)來檢測棧中的值是否被其他線程改變,如果被改變則CAS操作失敗。這種實現方法在CPU指令級別實現了原子操作,因此,其比使用synchronized來實現同步效率更高。

CAS操作過程都包含三個運算符:內存地址V、期望值E、新值N。當操作的時候,如果地址V上存放的值等於期望值E,則將地址V上的值賦為新值N,否則,不做任何操作,但是要返回原值是多少。這就保證比較和設置這兩個動作是原子操作。系統主要利用JNI(Java Native Interface,Java本地接口)來保證這個原子操作,它利用CPU硬件支持來完成,使用硬件提供swap和test_and_set指令,但CPU下同一指令的多個指令周期不可中斷,SMP(Symmetric Multi-Processing)中通過鎖總線支持這兩個指令的原子性

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM