1、什么是原子類
- 原子類的作用和鎖類似,是為了保證并發情況下的執行緒安全,不過原子類相比鎖,有一定優勢
- 粒度更細:他鎖的范圍更小
- 效率更高:相比于鎖,效率更高,除了高度競爭的情況
2、6類原子類
- Atomic*基本型別原子類:AtomicInteger、AtomicLong、AtomicBoolean
- Atomic*Array陣列型別原子類:AtomicIntegerArray、AtomicLongArray、AtomicBooleanArray
- Atomic*Reference參考型別原子類:AtomicReference、AtomicStampedRefence、AtomicMarkableRenfence
- Atomic*FieldUpdater升級型別原子類:AtomicIntegerfiedupdater、AtomicLongFieldUpdater、AtomicRefenceFieldUpdater
- Adder累加器:LongAdder、DoubleAdder
- Accumulator累加器:LongAccumulator、DoubleAccumulator
3、Atomic*基本型別原子類
基于CAS操作實作原子性
3.1、AtomicInteger常用方法
- get()獲取當前的值
- getAndSet(int newValue)獲取當前的值,并設定新的值
- getAndIncrement()獲取當前的值,并自增
- getAndDecrement()獲取當前的值,并自減
- getAndAdd(int delta)獲取當前的值,并加上預期的值
- compareAndSet(int expect, int update)如果當前的值等于預期的值,則以原子方式將值設定為輸入值
public class AtomicIntegerDemo1 implements Runnable { private static final AtomicInteger atomicInteger = new AtomicInteger(); public void incrementAtomic(){ atomicInteger.getAndIncrement(); } private static volatile int basicCount = 0; public void incrementBasic(){ basicCount++; } public void run() { for (int i = 0; i < 10000; i++) { incrementAtomic(); incrementBasic(); } } public static void main(String[] args) throws InterruptedException { AtomicIntegerDemo1 r = new AtomicIntegerDemo1(); Thread thread1 = new Thread(r); Thread thread2 = new Thread(r); thread1.start(); thread2.start(); thread1.join(); thread2.join(); System.out.println("原子類的結果" + atomicInteger.get()); System.out.println("普通變數的結果" + basicCount); } }
4、Atomic*Array陣列型別原子類
可以保證一個陣列中所有的原子操作
public class AtomicArrayDemo { public static void main(String[] args) throws InterruptedException { AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(1000); Incrementer incrementer = new Incrementer(atomicIntegerArray); Decrementer decrementer = new Decrementer(atomicIntegerArray); Thread[] threadsIncrement = new Thread[100]; Thread[] threadsDecrement = new Thread[100]; for (int i = 0; i < 100; i++) { threadsDecrement[i] = new Thread(decrementer); threadsIncrement[i] = new Thread(incrementer); threadsDecrement[i].start(); threadsIncrement[i].start(); } for (int i = 0; i < 100; i++) { threadsDecrement[i].join(); threadsIncrement[i].join(); } for (int i = 0; i < atomicIntegerArray.length(); i++) { if (atomicIntegerArray.get(i) != 0){ System.out.println("發現了非0值,位置"+i); } } System.out.println("運行結束"); } } class Decrementer implements Runnable{ private AtomicIntegerArray array; public Decrementer(AtomicIntegerArray array){ this.array = array; } public void run() { for (int i = 0; i < array.length(); i++) { array.getAndDecrement(i); } } } class Incrementer implements Runnable{ private AtomicIntegerArray array; public Incrementer(AtomicIntegerArray array){ this.array = array; } public void run() { for (int i = 0; i < array.length(); i++) { array.getAndIncrement(i); } } }
5、Atomic*Reference參考型別原子類
和AtomicInteger本質上沒有區別,這個是針對于物件
public class SpinLock { private AtomicReference<Thread> sign = new AtomicReference<>(); public void loock(){ Thread currentThread = Thread.currentThread(); while (!sign.compareAndSet(null, currentThread)){ System.out.println("自旋獲取失敗,再次嘗試"); } } public void unlock(){ Thread currentThread = Thread.currentThread(); sign.compareAndSet(currentThread, null); } public static void main(String[] args) { SpinLock spinLock = new SpinLock(); Runnable runnable = new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + "嘗試獲取自旋鎖"); spinLock.loock(); System.out.println(Thread.currentThread().getName() + "獲取到了自旋鎖"); try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } finally { spinLock.unlock(); System.out.println(Thread.currentThread().getName() + "釋放了自旋鎖"); } } }; new Thread(runnable).start(); new Thread(runnable).start(); } }主要是使用了compareAndSet()方法
6、Atomic*FieldUpdater升級型別原子類
將普通變數升級為具有原子功能
public class AtomicIntegerFieldUpdaterDemo implements Runnable { static Candidate tom; static Candidate peter; public static AtomicIntegerFieldUpdater<Candidate> scoreUpdater = AtomicIntegerFieldUpdater.newUpdater(Candidate.class, "score"); public void run() { for (int i = 0; i < 10000; i++) { peter.score++; // tom.score++; scoreUpdater.getAndIncrement(tom); } } public static class Candidate{ volatile int score; } public static void main(String[] args) throws InterruptedException { tom = new Candidate(); peter = new Candidate(); AtomicIntegerFieldUpdaterDemo r = new AtomicIntegerFieldUpdaterDemo(); Thread thread1 = new Thread(r); Thread thread2 = new Thread(r); thread1.start(); thread2.start(); thread1.join(); thread2.join(); System.out.println("普通的變數:"+peter.score); System.out.println("升級后的的變數:"+tom.score); } }
使用的是反射的機制,且不支持被static修飾的變數
7、Adder累加器
- 是Java8引入的,想對是比較新的一個類
- 高并發下LongAdder比AtomicLong效率高,不過本質是空間換時間
- 競爭激勵的時候,LongAdder把不同執行緒對應到不同的Cell上進行修改,降低了沖突的概率,是多段鎖的理念,提高了并發性
AtomicLong的耗時
public class AtomicLongDemo { public static void main(String[] args) { AtomicLong counter = new AtomicLong(0); ExecutorService executorService = Executors.newFixedThreadPool(20); long start = System.currentTimeMillis(); for (int i = 0; i < 10000; i++) { executorService.submit(new Task(counter)); } executorService.shutdown(); while (!executorService.isTerminated()){ } long end = System.currentTimeMillis(); System.out.println("耗費時間="+(end-start)); } private static class Task implements Runnable{ private AtomicLong counter; public Task(AtomicLong counter){ this.counter = counter; } public void run() { for (int i = 0; i < 10000; i++) { counter.incrementAndGet(); } } } }
使用LongAdder提升性能
public class LongAdderDemo { public static void main(String[] args) { LongAdder counter = new LongAdder(); ExecutorService executorService = Executors.newFixedThreadPool(20); long start = System.currentTimeMillis(); for (int i = 0; i < 10000; i++) { executorService.submit(new LongAdderDemo.Task(counter)); } executorService.shutdown(); while (!executorService.isTerminated()){ } long end = System.currentTimeMillis(); System.out.println("耗費時間="+(end-start)); } private static class Task implements Runnable{ private LongAdder counter; public Task(LongAdder counter){ this.counter = counter; } public void run() { for (int i = 0; i < 10000; i++) { counter.increment(); } } } }
AtomicLong每次自增都是需要flush和refersh
LongAdder,每個執行緒都會有自己的一個計數器,僅用來在自己的執行緒內計數,這樣一來就不會和其他執行緒的計數器干擾
LongAdder只使用于統計求和的場景
8、Accumulator累加器
適用于大的資料量計算,并且對計算順序不要求
public class LongAccumulatorDemo { public static void main(String[] args) { //LongAccumulator()后面的引數為x,后面傳遞的引數為y LongAccumulator accumulator = new LongAccumulator((x, y) -> x + y, 0); accumulator.accumulate(1); accumulator.accumulate(2); System.out.println(accumulator.get()); } }
9、CAS
- CAS作用于并發,保證一些列操作是原子性
- 思想:我認為V的值應該是A,如果是的話那我就將它改成B,如果不是A(說明被別人修改過了),那我就不修改了,避免多人同時修改出錯
- CAS有三個運算元:記憶體值V、預期值A、要修改的值B,當預期值A和記憶體值V相同時,才將記憶體值修改為B,否則什么都不做,最后回傳現在的值
- CAS最終是利用CPU的指令來完成,CPU保證了原子性
CAS的等價代碼:
public class SimulatedCAS { private volatile int value; //整個方法模擬cpu的一條指令,原子性 public synchronized int compareAndSwap(int expectedValue, int newValue){ int oldValue = value; if (oldValue == expectedValue){ value = newValue; } return oldValue; } }使用兩個執行緒來模擬多執行緒中CAS操作
public class TwoThreadCompetition implements Runnable{ private volatile int value; //整個方法模擬cpu的一條指令,原子性 public synchronized int compareAndSwap(int expectedValue, int newValue){ int oldValue = value; if (oldValue == expectedValue){ value = newValue; } return oldValue; } @Override public void run() { compareAndSwap(0, 1); } public static void main(String[] args) throws InterruptedException { TwoThreadCompetition r = new TwoThreadCompetition(); r.value = 0; Thread t1 = new Thread(r, "Thread1"); Thread t2 = new Thread(r, "Thread2"); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(r.value); } }典型的應用場景
- 樂觀鎖
- 并發容器
- 原子類
AtomicInteger中使用的原始碼
public class AtomicInteger extends Number implements java.io.Serializable { private static final long serialVersionUID = 6214790243416807050L; // setup to use Unsafe.compareAndSwapInt for updates //java無法訪問直接訪問 /unsafe 給我們提供了硬體級別的原子 private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final long valueOffset; static { try { valueOffset = unsafe.objectFieldOffset (AtomicInteger.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); } } private volatile int value; ...... public final int getAndAddInt(Object var1, long var2, int var4) { //do while自旋,不停的嘗試 int var5; do { var5 = this.getIntVolatile(var1, var2); } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4)); return var5; } }CAS的缺點:
- ABA問題:他只是檢查值是否相等,相等不代表沒有被修改過,原來是5,可能A執行緒改為7,B執行緒改為5,對比后,發現還是5,但是值確實被修改過,解決方案:版本號
- 自旋時間可能過長,因為他是一個自旋,對性能有很多的消耗
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/281204.html
標籤:其他
上一篇:Burp suite 工具 模塊






