業務場景:需要實現一個支持並發的計數功能
1、計數功能的基本實現是:
public class Increment{
private int count = 0;
public void add(){ count++; }
}
2、以上實現在並發環境下是不安全的,故修改方案1是加鎖synchronized:
public class Increment{
private int count = 0;
public synchronized void add(){ count++; }
}
//悲觀鎖,加鎖后只能有一個線程你執行++操作,其他線程需要等待
//不會出現count計數不准確的問題,線程安全
3、但是以上實現,會讓線程串行化,排隊等待獲取鎖、加鎖、處理數據、釋放鎖,並發下顯得不合理
修改方案2是使用Java並發包concurrent下的Atomic原子類
public class Increment{
private AtomicInteger count = new AtomicInteger();
public synchronized void add(){
count.incrementAndGet();
}
}
//多個線程可以並發的執行AtomicInteger的incrementAndGet()方法,把count的值累加1並返回累加后最新的值
//Atomic原子類底層用的是無鎖化的CAS機制,保證多線程修改一個數值的安全性
4、實現原理:
(1)每個線程都會先獲取當前的值,接着走一個原子的CAS操作,原子的意思就是這個CAS操作一定是自己完整執行完的,不會被別人打斷;
(2)在CAS操作里,比較一下,現在的值跟剛才我獲取到的那個值,是否相等,是則說明沒有人改過這個值,那么將它設置成累加1之后的一個值;
(3)同理,若有人在執行CAS時,發現自己之前獲取的值與當前的值不一樣,說明有其他人修改了值,導致CAS失敗,失敗之后進入一個循環,再次獲取值,再執行CAS操作。
5、CAS的問題:
每次去比較的時候,都發現值被別人改了,就會進入無限重復的循環。大量線程高並發時相當於空循環,自旋轉,性能和效率都不是特別好。
Java8的新類LongAdder,嘗試使用分段CAS以及自動分段遷移的方式來提升多線程高並發執行CAS操作的性能。核心思想是熱點分離,類似concurrentHashMap