最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

深入講解我們說的CAS自旋鎖到底是什么

 更新時間:2018年05月22日 10:59:24   作者:風箏  
這篇文章主要給大家介紹了關(guān)于我們說的CAS自旋鎖到底是什么的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

什么是自旋鎖

說道自旋鎖就要從多線程下的鎖機制說起,由于在多處理器系統(tǒng)環(huán)境中有些資源因為其有限性,有時需要互斥訪問(mutual exclusion),這時會引入鎖的機制,只有獲取了鎖的進程才能獲取資源訪問。即每次只能有且只有一個進程能獲取鎖,才能進入自己的臨界區(qū),同一時間不能兩個或兩個以上進程進入臨界區(qū),當退出臨界區(qū)時釋放鎖。

設(shè)計互斥算法時總是會面臨一種情況,即沒有獲得鎖的進程怎么辦?

通常有2種處理方式:

一種是沒有獲得鎖的調(diào)用者就一直循環(huán)在那里看是否該自旋鎖的保持者已經(jīng)釋放了鎖,這就是本文的重點——自旋鎖。他不用將線城阻塞起來(NON-BLOCKING)。

另一種是沒有獲得鎖的進程就阻塞(BLOCKING)自己,繼續(xù)執(zhí)行線程上的其他任務(wù),這就是 ——互斥鎖(包括內(nèi)置鎖Synchronized還有ReentrantLock等等)。

引言

CAS(Compare and swap),即比較并交換,也是實現(xiàn)我們平時所說的自旋鎖或樂觀鎖的核心操作。

它的實現(xiàn)很簡單,就是用一個預期的值和內(nèi)存值進行比較,如果兩個值相等,就用預期的值替換內(nèi)存值,并返回 true。否則,返回 false。

保證原子操作

任何技術(shù)的出現(xiàn)都是為了解決某些特定的問題, CAS 要解決的問題就是保證原子操作。原子操作是什么,原子就是最小不可拆分的,原子操作就是最小不可拆分的操作,也就是說操作一旦開始,就不能被打斷,知道操作完成。在多線程環(huán)境下,原子操作是保證線程安全的重要手段。舉個例子來說,假設(shè)有兩個線程在工作,都想對某個值做修改,就拿自增操作來說吧,要對一個整數(shù) i 進行自增操作,需要基本的三個步驟:

1、讀取 i 的當前值;

2、對 i 值進行加 1 操作;

3、將 i 值寫回內(nèi)存;

假設(shè)兩個進程都讀取了 i 的當前值,假設(shè)是 0,這時候 A 線程對 i 加 1 了,B 線程也 加 1,最后 i 的是 1 ,而不是 2。這就是因為自增操作不是原子操作,分成的這三個步驟可以被干擾。如下面這個例子,10個線程,每個線程都執(zhí)行 10000 次 i++ 操作,我們期望的值是 100,000,但是很遺憾,結(jié)果總是小于 100,000 的。

 static int i = 0;
 public static void add(){
 i++;
 }
 
 private static class Plus implements Runnable{
 @Override
 public void run(){
 for(int k = 0;k<10000;k++){
 add();
 }
 }
 }
 
 public static void main(String[] args) throws InterruptedException{
 Thread[] threads = new Thread[10];
 for(int i = 0;i<10;i++){
 threads[i] = new Thread(new Plus());
 threads[i].start();
 }
 for(int i = 0;i<10;i++){
 threads[i].join();
 }
 System.out.println(i);
 }

既然這樣,那怎么辦。沒錯,也許你已經(jīng)想到了,可以加鎖或者利用 synchronized 實現(xiàn),例如,將 add() 方法修改為如下這樣:

public synchronized static void add(){
 i++;
 }

或者,加鎖操作,例如下面使用 ReentrantLock (可重入鎖)實現(xiàn)。

private static Lock lock = new ReentrantLock();
 public static void add(){
 lock.lock();
 i++;
 lock.unlock();
 }

CAS 實現(xiàn)自旋鎖

既然用鎖或 synchronized 關(guān)鍵字可以實現(xiàn)原子操作,那么為什么還要用 CAS 呢,因為加鎖或使用 synchronized 關(guān)鍵字帶來的性能損耗較大,而用 CAS 可以實現(xiàn)樂觀鎖,它實際上是直接利用了 CPU 層面的指令,所以性能很高。

上面也說了,CAS 是實現(xiàn)自旋鎖的基礎(chǔ),CAS 利用 CPU 指令保證了操作的原子性,以達到鎖的效果,至于自旋呢,看字面意思也很明白,自己旋轉(zhuǎn),翻譯成人話就是循環(huán),一般是用一個無限循環(huán)實現(xiàn)。這樣一來,一個無限循環(huán)中,執(zhí)行一個 CAS 操作,當操作成功,返回 true 時,循環(huán)結(jié)束;當返回 false 時,接著執(zhí)行循環(huán),繼續(xù)嘗試 CAS 操作,直到返回 true。

其實 JDK 中有好多地方用到了 CAS ,尤其是java.util.concurrent包下,比如 CountDownLatch、Semaphore、ReentrantLock 中,再比如 java.util.concurrent.atomic 包下,相信大家都用到過 Atomic* ,比如 AtomicBoolean、AtomicInteger 等。

這里拿 AtomicBoolean 來舉個例子,因為它足夠簡單。

public class AtomicBoolean implements java.io.Serializable {
 private static final long serialVersionUID = 4654671469794556979L;
 // setup to use Unsafe.compareAndSwapInt for updates
 private static final Unsafe unsafe = Unsafe.getUnsafe();
 private static final long valueOffset;
 static {
 try {
 valueOffset = unsafe.objectFieldOffset
 (AtomicBoolean.class.getDeclaredField("value"));
 } catch (Exception ex) { throw new Error(ex); }
 }
 private volatile int value;
 
 public final boolean get() {
 return value != 0;
 }
 public final boolean compareAndSet(boolean expect, boolean update) {
 int e = expect ? 1 : 0;
 int u = update ? 1 : 0;
 return unsafe.compareAndSwapInt(this, valueOffset, e, u);
 }
}

這是 AtomicBoolean 的部分代碼,我們看到這里面又幾個關(guān)鍵方法和屬性。

1、使用了 sun.misc.Unsafe 對象,這個類提供了一系列直接操作內(nèi)存對象的方法,只是在 jdk 內(nèi)部使用,不建議開發(fā)者使用;

2、value 表示實際值,可以看到 get 方法實際是根據(jù) value 是否等于0來判斷布爾值的,這里的 value 定義為 volatile,因為 volatile 可以保證內(nèi)存可見性,也就是 value 值只要發(fā)生變化,其他線程是馬上可以看到變化后的值的;下一篇會講一下 volatile 可見性問題,歡迎關(guān)注

3、valueOffset 是 value 值的內(nèi)存偏移量,用 unsafe.objectFieldOffset 方法獲得,用作后面的 compareAndSet 方法;

4、compareAndSet 方法,這就是實現(xiàn) CAS 的核心方法了,在使用 AtomicBoolean 的這個方法時,只需要傳遞期望值和待更新的值即可,而它里面調(diào)用了 unsafe.compareAndSwapInt(this, valueOffset, e, u) 方法,它是個 native 方法,用 c++ 實現(xiàn),具體的代碼就不貼了,總之是利用了 CPU 的 cmpxchg 指令完成比較并替換,當然根據(jù)具體的系統(tǒng)版本不同,實現(xiàn)起來也有所區(qū)別,感興趣的可以自行搜一下相關(guān)文章。

使用場景

  • CAS 適合簡單對象的操作,比如布爾值、整型值等;
  • CAS 適合沖突較少的情況,如果太多線程在同時自旋,那么長時間循環(huán)會導致 CPU 開銷很大;

比如 AtomicBoolean 可以用在這樣一個場景下,系統(tǒng)需要根據(jù)一個布爾變量的狀態(tài)屬性來判斷是否需要執(zhí)行一些初始化操作,如果是多線程的環(huán)境下,避免多次重復執(zhí)行,可以使用 AtomicBoolean 來實現(xiàn),偽代碼如下:

private final static AtomicBoolean flag = new AtomicBoolean();
 if(flag.compareAndSet(false,true)){
 init();
 }

比如 AtomicInteger 可以用在計數(shù)器中,多線程環(huán)境中,保證計數(shù)準確。

ABA問題

CAS 存在一個問題,就是一個值從 A 變?yōu)?B ,又從 B 變回了 A,這種情況下,CAS 會認為值沒有發(fā)生過變化,但實際上是有變化的。對此,并發(fā)包下倒是有 AtomicStampedReference 提供了根據(jù)版本號判斷的實現(xiàn),可以解決一部分問題。

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

相關(guān)文章

  • PowerJob的MapProcessor工作流程源碼解讀

    PowerJob的MapProcessor工作流程源碼解讀

    這篇文章主要為大家介紹了PowerJob的MapProcessor工作流程源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2024-01-01
  • 實例分析java對象中淺克隆和深克隆

    實例分析java對象中淺克隆和深克隆

    在本篇文章中我們給大家分享了關(guān)于java對象中淺克隆和深克隆的相關(guān)知識點和相關(guān)代碼內(nèi)容,有興趣的朋友們學習下。
    2018-10-10
  • Java多線程中停止線程遇到線程阻塞的處理方法詳解

    Java多線程中停止線程遇到線程阻塞的處理方法詳解

    這篇文章主要介紹了Java多線程中停止線程遇到線程阻塞的處理方法詳解,在阻塞狀態(tài)下,線程會釋放CPU資源,從而允許其他線程執(zhí)行,線程阻塞是實現(xiàn)多線程編程中重要的概念,可以提高程序的效率和資源利用率,需要的朋友可以參考下
    2023-10-10
  • SpringBoot攔截器實現(xiàn)項目防止接口重復提交

    SpringBoot攔截器實現(xiàn)項目防止接口重復提交

    基于SpringBoot框架來開發(fā)業(yè)務(wù)后臺項目時,接口重復提交是一個常見的問題,本文主要介紹了SpringBoot攔截器實現(xiàn)項目防止接口重復提交,具有一定的參考價值,感興趣的可以了解一下
    2023-09-09
  • 詳解Java多線程編程中線程的啟動、中斷或終止操作

    詳解Java多線程編程中線程的啟動、中斷或終止操作

    在Java中start和tun方法可用被用來啟動線程,而用interrupt方法來中斷或終止線程,以下我們就來詳解Java多線程編程中線程的啟動、中斷或終止操作
    2016-07-07
  • Java中==和equals()的區(qū)別總結(jié)

    Java中==和equals()的區(qū)別總結(jié)

    ==和equals是我們面試中經(jīng)常會碰到的問題,那么它們之間有什么聯(lián)系和區(qū)別呢?這篇文章主要給大家介紹了關(guān)于Java中==和equals()區(qū)別的相關(guān)資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-07-07
  • Java探索之string字符串的應(yīng)用代碼示例

    Java探索之string字符串的應(yīng)用代碼示例

    這篇文章主要介紹了Java探索之string字符串的應(yīng)用代碼示例,具有一定參考價值,需要的朋友可以了解下。
    2017-10-10
  • 關(guān)于@JsonProperty和@JSONField注解的區(qū)別及用法

    關(guān)于@JsonProperty和@JSONField注解的區(qū)別及用法

    這篇文章主要介紹了關(guān)于@JsonProperty和@JSONField注解的區(qū)別及用法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • Java注解(annotation)簡述

    Java注解(annotation)簡述

    這篇文章主要介紹了使用java的注解(用在java類的方法上的注解)方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-08-08
  • jvm堆外內(nèi)存排查圖文舉例詳解

    jvm堆外內(nèi)存排查圖文舉例詳解

    Java應(yīng)用程序通過直接方式從操作系統(tǒng)中申請的內(nèi)存,叫堆外內(nèi)存,這篇文章主要給大家介紹了關(guān)于jvm堆外內(nèi)存排查的相關(guān)資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2023-12-12

最新評論

忻州市| 乌兰县| 泰州市| 平潭县| 桃源县| 荣成市| 古浪县| 和政县| 舟曲县| 安阳县| 凉城县| 洛扎县| 浙江省| 子洲县| 郸城县| 时尚| 道孚县| 舞钢市| 关岭| 武宁县| 永靖县| 绍兴县| 互助| 塔城市| 宝清县| 宾阳县| 彰化市| 株洲市| 静海县| 怀宁县| 濮阳市| 隆昌县| 班玛县| 嘉荫县| 庐江县| 鹿邑县| 蒙山县| 茶陵县| 成都市| 平昌县| 泸西县|