中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java 基本功 之 CAS

發布時間:2020-07-16 02:25:04 來源:網絡 閱讀:362 作者:菜鳥騫 欄目:編程語言


本文首發于個人公眾號《andyqian》,期待你的關注!

前言

在Java并發編程中,我們經常使用鎖對競爭資源予以并發控制,以解決資源競爭的問題。但無論是使用 Lock 還是 Synchronized,隨著鎖機制的引入,就不可避免的帶來另一個問題,也就鎖與解鎖時的上下文切換,線程等待 等性能問題。現在回過頭來看,在有些場景中,是否真的需要引入鎖才能解決競爭資源共享問題?答案是否定的,在JDK源碼中,也為我們實現了。就是今天要介紹的另外一種無鎖方案-CAS,它大量應用于JUC 包中,也是atomic包中各類的底層原理,其重要行可想而知。

CAS 簡介

CAS 全稱為:Compare And Swap (比較與替換),其核心思想是:將內存值 Value 與期望值 A 進行比較,如果兩者相等,則將其設置為新值 B,否則不進行任何操作。CAS操作非常高效,在我看來,其原因有二,其一:底層調用的是 sun.misc.Unsafe 類,操作的是內存值,非常高效。其二:在多線程環境下,始終只有一個線程獲得執行權,未獲得執行權的線程并不會掛起而造成阻塞,而是以操作CAS失敗后再次執行CAS操作,直至成功,這一個過程,在Java中稱之為 “自旋”。

源碼解析

Java 中 CAS 應用的十分廣泛,幕后英雄是sun.misc.Unsafe 類,單獨看Unsafe類的CAS操作可能有些茫然,以我們熟悉的 AtomicInteger 類中的 compareAndSet 方法為引子,再分析到 Unsafe類可能會更好些。下面為AtomicInteger 類中 compareAndSet 方法的源碼,如下所述:

public?final?boolean?compareAndSet(int?expect,?int?update)?{
????return?unsafe.compareAndSwapInt(this,?valueOffset,?expect,?update)}

方法入參中 expect 為期望值,update 為待更新值。繼續往下看,compareAndSet 方法內部使用到的是Unsafe.compareAndSwapInt()方法,如下所述:

public?final?native?boolean?compareAndSwapInt(Object?var1,?long?var2,?int?var4,?int?var5);

方法入參有四個,其中:

  1. Object var1 為對象。

  2. long var2 為 var1 對象的內存地址。

  3. int var4 為 內存地址 中的期望值。

  4. var5 為 待更新的值。

在Unsafe類中,同類的方法有以下幾個:

public?final?native?boolean?compareAndSwapObject(Object?var1,?long?var2,?Object?var4,?Object?var5);

public?final?native?boolean?compareAndSwapLong(Object?var1,?long?var2,?long?var4,?long?var6);

其實 Unsafe 類還給我們提供了一系列底層的API,由于篇幅原因,就不再展開說明,下次放單獨一篇文章中談談。

ABA 問題

在 CAS 中有一個特別經典的問題,也就是ABA。它說的是:內存值 Value 與期望值 A 進行比較前,Value已經發生過變化了,只不過是其變化后的值也為Value。從而造成從結果上看,其結果一致是一致的,(多發生于多線程條件下)當然這也是符合CAS 條件的。在大多數場景下,我們并不需要關心這種場景,在需要關心時,我們也可以使用JDK為我們提供了實現類 - AtomicStampedReference。在AomicStampedReference 類中,引入了標記位的概念,用于標記value值是否被修改過。結合value值 + 標記位是否一致,來判斷value值是否修改過。其源碼如下:

public?boolean?compareAndSet(V??expectedReference,?//?期望引用對象
?????????????????????????????????V?newReference,????//?新的引用對象
?????????????????????????????????int?expectedStamp,?//期望標志位
?????????????????????????????????int?newStamp)??//?新的標識位
????????Pair<V>?current?=?pair;??//?獲取對象與標識引用對
????????return
????????????expectedReference?==?current.reference?&&???//?期望對象引用是否等于當前引用對象?(是否發生變化)
????????????expectedStamp?==?current.stamp&&??????//?期望stamp?是否等于當前stamp
????????????((newReference?==?current.reference?&&???//新的引用對象是否等于當前引用對象,新的stamp是否等于當前stamp
??????????????newStamp?==?current.stamp)?||
?????????????casPair(current,?Pair.of(newReference,?newStamp)));??//進行pair?的cas操作
????}

其中 pair 為 對象引用與版本標記對象,其源碼如下:

private?static?class?Pair<T>?{
????????final?T?reference;
????????final?int?stamp;
????????private?Pair(T?reference,?int?stamp)?{
????????????this.reference?=?reference;
????????????this.stamp?=?stamp;
????????}
????????static?<T>?Pair<T>?of(T?reference,?int?stamp)?{
????????????return?new?Pair<T>(reference,?stamp);
????????}
????}

結語

在Java 中 CAS 應用的十分廣泛,包括但不限于:atomic,synchorized 底層原理等等。但需要明確的是 CAS 的存在并不是用來替換 lock 的,而是一種互補的關系。平常都在寫業務代碼,沒有更深層次的查看源碼,當查看源碼時,卻又是一件趣事,蠻好的!



相關閱讀:

《談談 996 背后的現象》

《重構不完全指南!》

《說說Java 位運算》

《上千行存儲過程有感!》

Java 基本功 之 CAS



向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

密云县| 资讯| 科技| 天津市| 嘉黎县| 平潭县| 怀仁县| 固镇县| 靖远县| 綦江县| 扎鲁特旗| 修文县| 保亭| 临猗县| 龙南县| 呈贡县| 革吉县| 旬邑县| 望城县| 古蔺县| 桂阳县| 建阳市| 洪泽县| 睢宁县| 穆棱市| 迁安市| 剑川县| 宜阳县| 温州市| 岢岚县| 廉江市| 抚顺市| 青神县| 永春县| 昭平县| 怀远县| 于田县| 肥西县| 汉川市| 壤塘县| 顺义区|