亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

目錄
幾種保證線程安全的方案 " >幾種保證線程安全的方案
1. 通過synchronized關鍵字實現(xiàn)同步:
2. 通過Lock鎖實現(xiàn)同步
3. 使用 Atomic 原子類
4. 使用 LongAdder 原子類
CAS理論 " >CAS理論
CAS的實現(xiàn) " >CAS的實現(xiàn)
首頁 Java Java面試題 面試真題:請你聊聊並發(fā)中的CAS 機制

面試真題:請你聊聊並發(fā)中的CAS 機制

Jul 26, 2023 pm 03:05 PM
cas

不知道同學們有沒有經歷過這樣的面試:

面試官:請你聊聊並發(fā)中的CAS機制吧
#小明:嗯,CAS是吧,好像聽過...我想想哈(大腦飛快思考)

?2分鐘過去了...
?空氣是死一般的沈靜.. .

面試官坐不住了,清了清喉嚨:咳... 那個,能簡單說說嗎?
小明憨憨一笑:嘿嘿,我好像忘記了...
面試官:哦,沒關係,今天的面試就到這吧,你回去等通知吧
小明垂頭喪氣地離開了...


別笑,小明其實是很多人的影子,在面試過程中民聊的同學不在少數(shù),當然我也包括在內,其實這反映出一個很殘酷的現(xiàn)實:基礎不紮實!

那麼問題來了,如何在面試中吊打麵試官,穩(wěn)如磐石?

學呀!光說有啥用,你得學啊,買的書你得看啊,買的課你得跟著練啊,別光打遊戲追劇了,想要變強,唯有禿頭!

現(xiàn)在是北京時間0:08,我在碼字寫文章,你呢?

面試真題:請你聊聊並發(fā)中的CAS 機制

一個小例子說說什麼是執(zhí)行緒安全性

##並發(fā)是Java程式設計的基礎,在我們日常的工作中,很多時候都會跟並發(fā)打交道,當然,這也是面試考察的重點。在同時程式設計中,被提起最多的概念是

線程安全,下面我們先來看一段程式碼,看看運行後會發(fā)生什麼:

public class Test {
    private static int inc = 0;

    public static void main(String[] args) {
     // 設置柵欄,保證主線程能獲取到程序各個線程全部執(zhí)行完之后的值
        CountDownLatch countDownLatch = new CountDownLatch(1000000);
        // 設置100個線程同時執(zhí)行
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
             // 循環(huán)10000次,對inc實現(xiàn) +1 操作
                for (int j = 0; j < 10000; j++) {
                    inc++;
                    countDownLatch.countDown();
                }
            }).start();
        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 運行完畢,期望獲取的結果是 1000000
        System.out.println("執(zhí)行完畢,inc的值為:" + inc);
    }
}

程式中,我創(chuàng)建了100個線程,每個線程中對共享變數(shù)inc進行累加10000次的操作,如果是同步執(zhí)行的話,inc最終的值應該是1000000,但我們知道在多執(zhí)行緒中,程式是並發(fā)執(zhí)行的,也就是說不同的執(zhí)行緒可能會同時讀取到主記憶體相同的值,例如這樣的場景:

  • 執(zhí)行緒A在某一個瞬間讀取了主記憶體的inc值為1000,它在自己的工作記憶體1,inc變成了1001;
  • 線程B在同樣的瞬間讀取到了主記憶體的inc值為1000,它也在自己的工作記憶體中對inc的值1, inc變成了1001;
  • 他們要往主記憶體寫入inc的值的時候並沒有做任何的同步控制,所以他們都有可能把自己工作內存的1001寫入到主內存;
  • 那麼很顯然主內存在進行兩次1 操作後,實際的結果只進行了一次1,變成了1001。

這就是一個很典型的多執(zhí)行緒並發(fā)修改共享變數(shù)所帶來的問題,那麼很顯然,它的運行結果也如我們分析的那樣,某些情況下達不到1000000:

執(zhí)行完畢,inc的值為:962370

有些人說透過volatile關鍵字可以解決這個問題,因為volatile可以保證執(zhí)行緒之間的可見性,也就是說執(zhí)行緒可以讀取到主記憶體最新的變數(shù)值,然後對其進行操作。

注意了,volatile只能保證線程的可見性,而不能保證線程操作的原子性,雖然線程讀取到了主記憶體的inc的最新值,但是讀取、inc 1、寫入主記憶體 是三步驟操作,所以volatile無法解決共享變數(shù)執(zhí)行緒安全的問題。

那麼要如何解決這個問題? Java為我們提供下面幾種解決方案。

幾種保證線程安全的方案

1. 通過synchronized關鍵字實現(xiàn)同步:

public class Test {
    private static int inc = 0;

    public static void main(String[] args) {
        // 設置柵欄,保證主線程能獲取到程序各個線程全部執(zhí)行完之后的值
        CountDownLatch countDownLatch = new CountDownLatch(1000000);
        // 設置100個線程同時執(zhí)行
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                // 循環(huán)10000次,對inc實現(xiàn) +1 操作
                for (int j = 0; j < 10000; j++) {
                 // 設置同步機制,讓inc按照順序執(zhí)行
                    synchronized (Test.class) {
                        inc++;
                    }

                    countDownLatch.countDown();
                }
            }).start();
        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("執(zhí)行完畢,inc的值為:" + inc);
    }
}

在上面的代碼中,我們給 inc ++ 外面加了一層代碼,使用 synchronized 設置類鎖,保證了代碼的同步執(zhí)行,這是一種基于JVM自身的機制來保障線程的安全性,如果在并發(fā)量比較大的情況下,synchronized 會升級為重量級的鎖,效率很低。synchronized無法獲取當前線程的鎖狀態(tài),發(fā)生異常的情況下會自動解鎖,但是如果線程發(fā)生阻塞,它是不會釋放鎖的

執(zhí)行結果:

執(zhí)行完畢,inc的值為:1000000

可以看到,這種方式是可以保證線程安全的。

2. 通過Lock鎖實現(xiàn)同步

public class Test {
    private static int inc = 0;
    private static Lock lock = new ReentrantLock();

    public static void main(String[] args) {
        // 設置柵欄,保證主線程能獲取到程序各個線程全部執(zhí)行完之后的值
        CountDownLatch countDownLatch = new CountDownLatch(1000000);

        // 設置100個線程同時執(zhí)行
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                // 循環(huán)10000次,對inc實現(xiàn) +1 操作
                for (int j = 0; j < 10000; j++) {
                 // 設置鎖
                    lock.lock();
                    try {
                        inc++;
                    } finally {
                     // 解鎖
                        lock.unlock();
                    }
                    countDownLatch.countDown();
                }
            }).start();
        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("執(zhí)行完畢,inc的值為:" + inc);
    }
}

ReentrantLock的底層是通過AQS + CAS來實現(xiàn)的,在并發(fā)量比較小的情況下,它的性能不如 synchronized,但是隨著并發(fā)量的增大,它的性能會越來越好,達到一定量級會完全碾壓synchronized。并且Lock是可以嘗試獲取鎖的,它通過代碼手動去控制解鎖,這點需要格外注意。

執(zhí)行結果:

執(zhí)行完畢,inc的值為:1000000

3. 使用 Atomic 原子類

public class Test {
    private static AtomicInteger inc = new AtomicInteger();

    public static void main(String[] args) {
        // 設置柵欄,保證主線程能獲取到程序各個線程全部執(zhí)行完之后的值
        CountDownLatch countDownLatch = new CountDownLatch(1000000);

        // 設置100個線程同時執(zhí)行
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                // 循環(huán)10000次,對inc實現(xiàn) +1 操作
                for (int j = 0; j < 10000; j++) {
                    inc.getAndAdd(1);
                    countDownLatch.countDown();
                }
            }).start();
        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("執(zhí)行完畢,inc的值為:" + inc.get());
    }
}

AtomicInteger 底層是基于 CAS 的樂觀鎖實現(xiàn)的,CAS是一種無鎖技術,相對于前面的方案,它的效率更高一些,在下面會詳細介紹。

執(zhí)行結果:

執(zhí)行完畢,inc的值為:1000000

4. 使用 LongAdder 原子類

public class Test {
    private static LongAdder inc = new LongAdder();

    public static void main(String[] args) {
        // 設置柵欄,保證主線程能獲取到程序各個線程全部執(zhí)行完之后的值
        CountDownLatch countDownLatch = new CountDownLatch(1000000);

        // 設置100個線程同時執(zhí)行
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                // 循環(huán)10000次,對inc實現(xiàn) +1 操作
                for (int j = 0; j < 10000; j++) {
                    inc.increment();
                    countDownLatch.countDown();
                }
            }).start();
        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("執(zhí)行完畢,inc的值為:" + inc.intValue());
    }
}

LongAdder 原子類在 JDK1.8 中新增的類,其底層也是基于 CAS 機制實現(xiàn)的。適合于高并發(fā)場景下,特別是寫大于讀的場景,相較于 AtomicInteger、AtomicLong 性能更好,代價是消耗更多的空間,以空間換時間。

執(zhí)行結果:

執(zhí)行完畢,inc的值為:1000000

CAS理論

講到現(xiàn)在,終于我們今天的主角要登場了,她就是CAS。

CAS的意思是比較與交換(Compare And Swap),它是樂觀鎖的一種實現(xiàn)機制。

什么是樂觀鎖?通俗的來說就是它比較樂觀,每次在修改變量的值之前不認為別的線程會修改變量,每次都會嘗試去獲得鎖,如果獲取失敗了,它也會一直等待,直到獲取鎖為止。說白了,它就是打不死的小強。

而悲觀鎖呢,顧名思義,就比較悲觀了,每次在修改變量前都會認為別人會動這個變量,所以它會把變量鎖起來,獨占,直到自己修改完畢才會釋放鎖。說白了,就是比較自私,把好東西藏起來自己偷偷享用,完事了再拿出來給別人。像之前的synchronized關鍵字就是悲觀鎖的一種實現(xiàn)。

CAS是一種無鎖原子算法,它的操作包括三個操作數(shù):需要讀寫的內存位置(V)、預期原值(A)、新值(B)。僅當 V值等于A值時,才會將V的值設為B,如果V值和A值不同,則說明已經有其他線程做了更新,則當前線程繼續(xù)循環(huán)等待。最后,CAS 返回當前V的真實值。CAS 操作時抱著樂觀的態(tài)度進行的,它總是認為自己可以成功完成操作。

CAS的實現(xiàn)

在Java中,JUC的atomic包下提供了大量基于CAS實現(xiàn)的原子類:

面試真題:請你聊聊並發(fā)中的CAS 機制

我們以AtomicInteger來舉例說明。

AtomicInteger類內部通過一個Unsafe類型的靜態(tài)不可變的變量unsafe來引用Unsafe的實例。

 // setup to use Unsafe.compareAndSwapInt for updates
private static final Unsafe unsafe = Unsafe.getUnsafe();

然后,AtomicInteger類用value保存自身的數(shù)值,并用get()方法對外提供。注意,它的value是使用volatile修飾的,保證了線程的可見性。

private volatile int value;

/**
 * Creates a new AtomicInteger with the given initial value.
 *
 * @param initialValue the initial value
 */
public AtomicInteger(int initialValue) {
    value = initialValue;
}

/**
 * Gets the current value.
 *
 * @return the current value
 */
public final int get() {
    return value;
}

一路跟蹤incrementAndGet方法到的末尾可以看到是一個native的方法:

/**
 * Atomically increments by one the current value.
 *
 * @return the updated value
 */
public final int incrementAndGet() {
    return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}

//  getAndAddInt 方法
public final int getAndAddInt(Object var1, long var2, int var4) {
    int var5;
    do {
        var5 = this.getIntVolatile(var1, var2);
    } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

    return var5;
}

// compareAndSet方法
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

可以看到其實incrementAndGet內部的原理就是通過compareAndSwapInt調用底層的機器指令不斷比較內存舊值和期望的值,如果比較返回false就繼續(xù)循環(huán)比較,如果返回true則將當前的新值賦給內存里的值,本次處理完畢。

由此我們知道,原子類實現(xiàn)的自增操作可以保證原子性的根本原因在于硬件(處理器)的相關指令支持。將語義上需要多步操作的行為通過一條指令來完成,CAS指令可以達到這個目的。

CAS的缺點

  • 作為樂觀鎖定的一種實現(xiàn),當多執(zhí)行緒競爭資源激烈的情況下,多個執(zhí)行緒會發(fā)生自旋等待,會消耗一定的CPU資源。
  • CAS不可避免會出現(xiàn)ABA的問題,關於ABA問題的詮釋和解決方案,可以參考我的這篇文章:面試官問你:你知道什麼是ABA問題嗎?


好了,本期關於CAS的分享就到這裡結束了。 並發(fā)作為Java程式設計的基石,是一個非常重要的知識點,如果同學們對這塊的掌握比較薄弱,希望在讀完文章後能自己動手敲敲程式碼,思考一下什麼是CAS,有哪些優(yōu)缺點,實作方式有哪些。 當然,並發(fā)是一個非常大的概念,這裡只是拋磚引玉,提到了其中的一個小知識點,給出了我自己學習的一點心得體會。 如果有闡述不到位或錯誤的地方,請私訊我一起討論,感謝!

我是程式設計師青戈,本期的面試問題分享到這裡就結束了,想提升自己,進階大工廠的同學一定要關注我的公眾號:Java學習指南,這裡每天會從實際的面試出發(fā)帶你學習和總結Java相關的知識,幫助你擴充技術棧,提昇個人實力。我們下期見~

以上是面試真題:請你聊聊並發(fā)中的CAS 機制的詳細內容。更多資訊請關注PHP中文網(wǎng)其他相關文章!

本網(wǎng)站聲明
本文內容由網(wǎng)友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發(fā)現(xiàn)涉嫌抄襲或侵權的內容,請聯(lián)絡admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺化網(wǎng)頁開發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Laravel 教程
1597
29
PHP教程
1488
72
透過 CAS(Central Authentication Service) 實現(xiàn) PHP 安全驗證 透過 CAS(Central Authentication Service) 實現(xiàn) PHP 安全驗證 Jul 24, 2023 pm 12:49 PM

透過CAS(CentralAuthenticationService)實現(xiàn)PHP安全驗證隨著網(wǎng)際網(wǎng)路的快速發(fā)展,使用者權限管理和身分驗證越來越重要。在開發(fā)WEB應用程式時,保護使用者資料和防止未經授權存取是至關重要的。為了實現(xiàn)這一目標,我們可以使用CAS(CentralAuthenticationService)來進行PHP的安全驗證。 CAS

java CAS的概念是什麼 java CAS的概念是什麼 May 03, 2023 pm 09:34 PM

1.說明當多個線程同時對某個資源進行CAS操作時,只有一個線程成功,但不會堵塞其他線程,其他線程只會收到操作失敗的訊號??梢奀AS其實是樂觀的鎖。 2.實例跟隨AtomInteger的程式碼,我們可以發(fā)現(xiàn)最終呼叫的是sum.misc.Unsafe??纯碪nsafe這個名字,它是一個不安全的類別,它利用了Java類別和可見性規(guī)則中恰到好處的漏洞。為了速度,Unsafe在Java的安全標準上做出了一些妥協(xié)。 publicfinalnativebooleancompareAndSwapInt(Objec

java的CAS怎麼應用 java的CAS怎麼應用 Apr 18, 2023 pm 06:37 PM

CAS解釋:CAS(compareandswap),比較並交換??梢越鉀Q多執(zhí)行緒並行情況下使用鎖造成效能損耗的一種機制。CAS運算包含三個運算元—記憶體位置(V)、預期原值(A)和新值(B)。如果記憶體位置的值與預期原值相匹配,那麼處理器會自動將該位置值更新為新值。否則,處理器不做任何操作。一個執(zhí)行緒從主記憶體得到num值,並對num進行操作,寫入值的時候,執(zhí)行緒會把第一次取到的num值和主記憶體中num值進行比較,如果相等,就會改變後的num寫入主內存,如果不相等,則一直循環(huán)對比,知道成功為止。 CAS產

CAS與java樂觀鎖怎麼用 CAS與java樂觀鎖怎麼用 May 01, 2023 pm 08:07 PM

什麼是CASCAS是CompareAndSwap,即比較和交換。為什麼CAS沒有用到鎖還能保證並發(fā)情況下安全的操作數(shù)據(jù)呢,名字其實非常直觀的表明了CAS的原理,具體修改數(shù)據(jù)過程如下:用CAS操作數(shù)據(jù)時,將數(shù)據(jù)原始值和要修改的值一併傳遞給方法比較當前目標變數(shù)值與傳進去的原始值是否相同如果相同,表示目標變數(shù)沒有被其他執(zhí)行緒修改,直接修改目標變數(shù)值即可如果目標變數(shù)值與原始值不同,那麼證明目標變數(shù)已經被其他線程修改過,本次CAS修改失敗從上述過程可以看到CAS其實保證的是安全的修改數(shù)據(jù),但是修改存在失敗的

Java有鎖並發(fā)、無鎖並發(fā)和CAS實例分析 Java有鎖並發(fā)、無鎖並發(fā)和CAS實例分析 May 23, 2023 pm 01:34 PM

有鎖並發(fā)對於大多數(shù)程式設計師(當然我也基本上是其中一員),並發(fā)程式幾乎就等價於為相關資料結構加上一個鎖(Mutex)。例如如果我們需要一個支援並發(fā)的棧,那最簡單的方法就是給一個單執(zhí)行緒的棧加上鎖定std::sync::Mutex。 (加上Arc是為了能讓多個執(zhí)行緒都擁有堆疊的所有權)usestd::sync::{Mutex,Arc};#[derive(Clone)]structConcurrentStack{inner:Arc,}implConcurrentStack{pubfnnew()-> Self{

面試真題:請你聊聊並發(fā)中的CAS 機制 面試真題:請你聊聊並發(fā)中的CAS 機制 Jul 26, 2023 pm 03:05 PM

程式中,我創(chuàng)建了100個線程,每個線程中對共享變數(shù)inc進行累加10000次的操作,如果是同步執(zhí)行的話,inc最終的值應該是1000000,但我們知道在多線程中,程式是並發(fā)執(zhí)行的,也就是說不同的執(zhí)行緒可能會同時讀取到主記憶體相同的值

面試官問你:你知道什麼是ABA問題嗎? 面試官問你:你知道什麼是ABA問題嗎? Jul 26, 2023 pm 03:09 PM

本期關於CAS領域的一個經典ABA問題的解析,不知道你在實際的工作中有沒有遇到過,但是在面試中這塊是並發(fā)知識考查的重點。如果你還沒接觸過這類的問題,我的建議是你自己將上面的程式碼執(zhí)行一下

基於springboot怎麼搭建CAS Client客戶端 基於springboot怎麼搭建CAS Client客戶端 May 14, 2023 am 10:46 AM

1.新建springboot專案並引入依賴org.jasig.cas.clientcas-client-support-springboot3.6.22.設定@EnableCasClient註解packagecom.codetiler.demo;importorg.jasig.cas.client.boot.configuration.EnableCasClientimportorg.jasig.cas.client.boot.configuration.EnableCasClientimportorg. springframework.boot.SpringApplication;importorg.spring

See all articles