atomic對於數據原子性操作較方便處理,即當多個線程對同一個變量進行更新時,僅有一個線程可以成功,而未能成功的形成會像自旋鎖一樣,繼續嘗試,一直等到執行成功。
原子性原理:
一、i++的原子性,i++的操作,分為三部分:"讀-改-寫"
int i = 10;
i = i++; //10
int temp = i;
i = i + 1;
i = temp;
二、原子變量:java.util.concurrent.atomic包下提供了常用的原子變量
1.volatile 保證內存可見性
2.CAS(Compare-And-Swap)算法保證數據的原子性
CAS算法是硬件對於並發操作共享數據的支持。
CAS包含了三個操作數:
內存值:V
預估值:A
更新值:B
當且僅當V == A, V = B,否則,不做任何操作。
|
嗯~~~理解以及使用直接上代碼………………
3 import java.util.concurrent.atomic.AtomicInteger; 4 import java.util.function.DoubleUnaryOperator; 5 import java.util.function.IntUnaryOperator; 6 import static java.lang.Float.*; 7 8 public class AtomicPrac { 9 public static void main(String[] args) { 10 AtomicDemo atomicDemo = new AtomicDemo(); 11 atomicDemo.setNumberA(new AtomicInteger(3)); 12 for (int i = 1; i <= 10; i++) { 13 new Thread(atomicDemo).start(); 14 } 15 16 AtomicInteger j=new AtomicInteger(4); 17 System.out.println(j.incrementAndGet()); 18 System.out.println(updateAndGetInt(j,p -> p/2 )); 19 20 //double型數據 21 AtomicFloat k = new AtomicFloat(5); 22 System.out.println(updateAndGetDouble(k,p -> p/2 )); 23 24 } 25 //模擬底層實現: 26 public static float updateAndGetDouble(AtomicFloat i, DoubleUnaryOperator operator){ 27 while(true){ 28 float prev=i.get();//得到當前值 29 float next=(float) operator.applyAsDouble(prev);//將舊值傳入,讓接口的某個方法完成具體運算,返回計算結果 30 //重寫compareAndSet 31 if(i.compareAndSet(prev,next)){ 32 return next; 33 } 34 } 35 } 36 public static int updateAndGetInt(AtomicInteger i, IntUnaryOperator operator){ 37 while(true){ 38 int prev=i.get();//得到當前值 39 int next=operator.applyAsInt(prev);//將舊值傳入,讓接口的某個方法完成具體運算,返回計算結果 40 if(i.compareAndSet(prev,next)){ 41 return next; 42 } 43 } 44 } 45 //模擬底層實現: 46 } 47 class AtomicDemo implements Runnable { 48 public AtomicInteger numberA; 49 50 public void run() { 51 try { 52 Thread.sleep(200); 53 } catch (InterruptedException e) { 54 e.printStackTrace(); 55 } 56 System.out.println(Thread.currentThread().getName() + ":" + getNumberA()); 57 } 58 59 public int getNumberA() { 60 return numberA.updateAndGet(x -> x*2); 61 } 62 63 public void setNumberA(AtomicInteger numberA) { 64 this.numberA = numberA; 65 } 66 } 67 68 //對於使用雙精度型的數據對應AtomicLong 自定義AtomicDouble 轉換doubleToLongBits(1.00); 69 //對於使用單精度型的數據對應AtomicInteger 自定義AtomicFloat 轉換floatToIntBits(1.00); 70 class AtomicFloat extends Number { 71 72 private AtomicInteger bits; 73 74 public AtomicFloat() { 75 this(0f); 76 } 77 78 public AtomicFloat(float initialValue) { 79 bits = new AtomicInteger(floatToIntBits(initialValue)); 80 } 81 82 public final boolean compareAndSet(float expect, float update) { 83 return bits.compareAndSet(floatToIntBits(expect), 84 floatToIntBits(update)); 85 } 86 87 public final void set(float newValue) { 88 bits.set(floatToIntBits(newValue)); 89 } 90 91 public final float get() { 92 return intBitsToFloat(bits.get()); 93 } 94 95 public float floatValue() { 96 return get(); 97 } 98 99 public final float getAndSet(float newValue) { 100 return intBitsToFloat(bits.getAndSet(floatToIntBits(newValue))); 101 } 102 103 public final boolean weakCompareAndSet(float expect, float update) { 104 return bits.weakCompareAndSet(floatToIntBits(expect), 105 floatToIntBits(update)); 106 } 107 108 public double doubleValue() { return (double) floatValue(); } 109 public int intValue() { return (int) get(); } 110 public long longValue() { return (long) get(); } 111 }
運行結果:
5
2
2.5
Thread-0:6
Thread-1:12
Thread-4:24
Thread-9:192
Thread-8:384
Thread-3:768
Thread-2:96
Thread-5:48
Thread-6:3072
Thread-7:1536