您好,我是湘王,這是我的部落格園,歡迎您來,歡迎您再來~
在JDK1.5之前,Java的多執行緒都是靠synchronized來保證同步的,這會引起很多效能問題,例如死鎖。但隨著Java的不斷完善,JNI(Java Native Interface)使得Java能越過JVM直接呼叫本地方法,例如CAS。
CAS是Compare And Swap(比較與交換)的縮寫,它用於實現多執行緒同步的原子指令,允許演演算法執行讀-修改-寫操作,而無需擔心其他執行緒同時修改變數。說人話,意思就是它的操作過程足夠細微,以至於執行緒都奈何不了它。
所謂原子指令就是指不會被執行緒排程機制打斷的操作指令,這種操作一旦開始,就一直執行到結束,中間不會有任何執行緒切換,即要麼全部完成,要麼全部中斷。換一種說法,就是CAS可以保證Java運算實現我們想要的操作而無需擔心會受到多執行緒的影響。
某種程度上,CAS可以用來取代synchronized的強制同步,提升效能。其實整個java.util.concurrent包都是建立在CAS之上的,尤其是Java中大多數鎖的實現基礎類別AbstractQueuedSynchronizer,更是以CAS為基礎,提供了一系列的獨佔鎖、共用鎖、可重入鎖、自旋鎖、讀寫鎖等多執行緒控制手段(這在後面會說)。就像圖中那樣:
Java對CAS的實現都在java.util.concurrent.atomic包下(java.util.concurrent也簡稱JUC,這是個簡稱。所以如果有面試官說想讓你談談JUC相關的問題,不要一臉懵,否則會被立即淘汰)。以AtomicInteger為例,從原始碼可以看出CAS操作都是通過sun包下Unsafe類實現,而Unsafe類中的方法都是native方法,由本地實現,和作業系統、CPU都有關係。CAS有一個比較通用的實現模式:
1、首先宣告(共用)變數為volatile
2、然後使用CAS的原子條件來更新
3、同時配合volatile的可見性來實現執行緒之間的同步
前面講過,不用深究volatile關鍵字的用途,因為隨著機器設定的豪華,其實這個關鍵字已經沒啥用了,而且也可以看到,在CAS裡面也有大量出現,JDK已經替你用好了,自己如果不太熟悉就不要用了。CAS相關類結構圖是:
還是老規矩,用程式碼來舉例:
/** * 僅用AtomicInteger實現CAS * * @author 湘王 */ public class AtomicIntegerTester1 { // 使用AtomicInteger實現CAS,有沒有volatile都不影響 public static volatile AtomicInteger atomicInteger = new AtomicInteger(0); public static void main(String[] args) throws InterruptedException { ExecutorService executor = Executors.newFixedThreadPool(3); for (int i = 0; i < 20; i++) { Runnable runnable = new Runnable() { @Override public void run() { atomicInteger.getAndIncrement(); } }; executor.submit(runnable); } // 為了觀察效果休眠,但實際生產環境中肯定不允許 Thread.sleep(100); executor.shutdown(); System.out.println(atomicInteger.get()); } } /** * 用AtomicIntegerFieldUpdater實現CAS * * @author 湘王 */ public class AtomicIntegerTester2 { /* * 使用AtomicIntegerFieldUpdater實現CAS,相關計算欄位必須用volatile修飾,不然拋異常 * Caused by: java.lang.IllegalArgumentException: Must be volatile type * */ public volatile int count = 0; public static final AtomicIntegerFieldUpdater<AtomicIntegerTester2> lockUpdate = AtomicIntegerFieldUpdater.newUpdater(AtomicIntegerTester2.class, "count"); public int increase(int inc) { return lockUpdate.addAndGet(this, inc); } public int get() { return lockUpdate.get(this); } public static void main(String[] args) throws InterruptedException { AtomicIntegerTester2 tester = new AtomicIntegerTester2(); ExecutorService executor = Executors.newFixedThreadPool(3); for (int i = 0; i < 20; i++) { Runnable runnable = new Runnable() { @Override public void run() { tester.increase(1); } }; executor.submit(runnable); } // 為了觀察效果休眠,但實際生產環境中肯定不允許 Thread.sleep(100); executor.shutdown(); System.out.println(tester.get()); } }
CAS的內容並不多,可以看看它的原始碼,還是比較有意思的。
感謝您的大駕光臨!諮詢技術、產品、運營和管理相關問題,請關注後留言。歡迎騷擾,不勝榮幸~