標籤:問題 java ima style 原子性 i++ 效率 cin rup
上一節討論了 volatile關鍵字,volatile關鍵字修飾的作用是不具有 "原子性" 和 "互斥性的"
例如 i++ 操作 就不是一個原子性的操作,i++ 其實分為3個步驟進行 "讀-改-寫"
int temp = i;
i = i + 1;
i= temp;
先看一段代碼:
package com.java.juc;public class TestAtomicDemo { public static void main(String[] args) { AtomicDemo ad = new AtomicDemo(); for(int i = 0;i<10;i++){ new Thread(ad).start(); } }}class AtomicDemo implements Runnable{ private int seriesNumber = 0; public void run() { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(getSeriesNumber()); } public int getSeriesNumber() { return seriesNumber++; }}
建立10個線程,每個線程對變數進行+1操作,
運行結果會出現如下等問題:
0
5
4
3
2
1
0
6
7
8
出現這種情況的主要原因就是 i++不是一個 原子性 操作
解決此問題的方法可以使用 原子變數
原子變數:jdk1.5以後 java.util.concurrent.atomic包下提供了常用的原子變數。
原子變數底層主要是有兩個作用:
1.volatile 保證記憶體可見度
2.CAS(compare-And-Swap)保證資料的原子性
CAS 演算法是硬體對於並行作業共用資料的支援
CAS 包含了三個運算元:
記憶體值 V
預估值 A
更新值 B
若且唯若 V== A 時,V = B. 否則將不做任何操作。
使用原子變數比鎖的效率要高很多,使用鎖時等待的線程會進入阻塞,使用Atomic進行等待的線程並不會進入阻塞狀態,還是持有cpu資源,只是不斷詢問是否該輪到他執行了。
使用 原子變數進行改寫
package com.java.juc;import java.util.concurrent.atomic.AtomicInteger;public class TestAtomicDemo { public static void main(String[] args) { AtomicDemo ad = new AtomicDemo(); for(int i = 0;i<10;i++){ new Thread(ad).start(); } }}class AtomicDemo implements Runnable{// private int seriesNumber = 0; private AtomicInteger seriesNumber = new AtomicInteger(); public void run() { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(getSeriesNumber()); } public int getSeriesNumber() { return seriesNumber.getAndIncrement(); }}
原子變數與CAS演算法