欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

java多線程編程必備volatile與synchronized深入理解

 更新時(shí)間:2023年04月12日 10:02:22   作者:玄明Hanko  
這篇文章主要介紹了java多線程編程必備volatile與synchronized的深入理解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

Volatile概述

Volatile是Java中的一種輕量級(jí)同步機(jī)制,用于保證變量的可見性和禁止指令重排。當(dāng)一個(gè)變量被聲明為Volatile類型時(shí),任何修改該變量的操作都會(huì)立即被所有線程看到。也就是說,Volatile修飾的變量在每次修改時(shí)都會(huì)強(qiáng)制將修改刷新到主內(nèi)存中,具有很好的可見性和線程安全性。

上圖可以看到在多線程編程中,線程沒有直接操作主內(nèi)存,而是把主內(nèi)存中的數(shù)據(jù)拷貝到工作內(nèi)存中也就是共享變量副本的方式操作變量。當(dāng)一個(gè)變量被多個(gè)線程共享時(shí),如果其中一個(gè)線程修改了這個(gè)變量的值,另一個(gè)線程在讀取這個(gè)變量時(shí)可能會(huì)得到過期的值。這是因?yàn)榫€程之間存在緩存不一致的問題。

使用 volatile 關(guān)鍵字可以解決這個(gè)問題。volatile 保證了對(duì)該變量的訪問都是直接針對(duì)主內(nèi)存中的變量進(jìn)行的,而不是訪問線程本地的緩存。因此,當(dāng)一個(gè)線程修改了這個(gè)變量的值,其他線程能夠立即看到這個(gè)變化,避免了緩存不一致的問題。

具體實(shí)現(xiàn)原理是,在使用 volatile 關(guān)鍵字修飾的變量進(jìn)行讀寫操作時(shí),會(huì)禁止 CPU 的緩存優(yōu)化,每次操作都要直接讀寫主內(nèi)存。同時(shí),在進(jìn)行讀操作時(shí),也會(huì)強(qiáng)制從主內(nèi)存中讀取最新的值,而不是使用線程本地的緩存。這樣就可以保證多線程之間的變量訪問是同步、可見的。

Synchronized概述

Synchronized是Java中的一種重量級(jí)同步機(jī)制,用于保證線程安全和排除數(shù)據(jù)競(jìng)爭(zhēng)。當(dāng)一個(gè)方法被聲明為Synchronized時(shí),同一時(shí)間只有一個(gè)線程可以訪問該方法,其他線程必須等待。這樣可以避免多個(gè)線程同時(shí)訪問共享資源導(dǎo)致數(shù)據(jù)不一致的問題。

Volatile與Synchronized的區(qū)別

(1)Volatile是一種輕量級(jí)的同步機(jī)制,Synchronized是一種重量級(jí)的同步機(jī)制。

(2)Volatile用于保證變量的可見性和禁止指令重排,Synchronized用于排除數(shù)據(jù)競(jìng)爭(zhēng)和保證線程安全。

(3)Volatile不能保證變量的原子性,Synchronized可以保證同步代碼塊的原子性。

(4)Volatile的性能遠(yuǎn)高于Synchronized,但只適用于變量的情況,而Synchronized則適用于任意類型的對(duì)象或代碼塊。

(5)volatile修飾變量,僅用于變量級(jí)(不會(huì)造成線程阻塞),線程讀寫時(shí)均刷新內(nèi)存,只保證可見性。volatile還可以禁止指令重排。

(6)synchronized鎖變量或代碼段,鎖級(jí)(會(huì)造成線程阻塞),能保證可見性與原子性

使用場(chǎng)景

1 Volatile的使用場(chǎng)景

由于Volatile的可見性和禁止指令重排的特點(diǎn),其在一些特定的場(chǎng)景下非常有用,例如:

(1)用于控制線程的開關(guān)、狀態(tài)標(biāo)志、計(jì)數(shù)器等變量;

(2)用于發(fā)布一些不變的對(duì)象,例如單例模式中的實(shí)例;

(3)用于性能調(diào)優(yōu),避免鎖競(jìng)爭(zhēng),例如CAS算法等。

以下是使用Java編寫一個(gè)演示volatile關(guān)鍵字的簡單示例:

    public class VolatileDemo {
        private volatile boolean isRunning = true;
        public void start() {
            System.out.println("Starting the thread...");
            new Thread(() -> {
                while (isRunning) {
                    // do some work here
                }
                System.out.println("Thread stopped.");
            }).start();
        }
        public void stop() {
            System.out.println("Stopping the thread...");
            isRunning = false;
        }
        public static void main(String[] args) throws InterruptedException {
            VolatileDemo demo = new VolatileDemo();
            demo.start();
            // wait for 3 seconds
            Thread.sleep(3000);
            demo.stop();
        }
    }

在上述示例中,我們創(chuàng)建了一個(gè)名為VolatileDemo的類,并聲明了一個(gè)volatile變量isRunning。此變量用于指示線程是否應(yīng)該繼續(xù)運(yùn)行。在start()方法中,我們啟動(dòng)了一個(gè)新線程,并在while循環(huán)中檢查isRunning變量的值。由于isRunning變量是volatile類型的,因此在不同的線程之間更改它的值時(shí),該值將始終保持同步。在stop()方法中,我們將isRunning變量的值設(shè)置為false,以便使線程停止運(yùn)行。在main()方法中,我們創(chuàng)建了一個(gè)VolatileDemo對(duì)象并調(diào)用start()方法來開始線程的執(zhí)行。然后,我們等待3秒鐘,隨后調(diào)用stop()方法來停止線程的執(zhí)行。由于isRunning變量是volatile類型的,因此線程能夠及時(shí)地檢測(cè)到isRunning變量的更改,從而停止線程的執(zhí)行。

2 Synchronized的使用場(chǎng)景

Synchronized機(jī)制由于其強(qiáng)制性的同步性,在保證線程安全和數(shù)據(jù)完整性的同時(shí),也會(huì)帶來一些性能上的開銷。因此,在使用Synchronized時(shí)需要控制同步的范圍和頻率,適當(dāng)使用Synchronized可以提高程序的效率和可靠性。使用Synchronized的場(chǎng)景包括:

(1)對(duì)共享變量的訪問和修改,例如在多線程情況下對(duì)數(shù)據(jù)進(jìn)行同步處理;

(2)對(duì)類實(shí)例化的構(gòu)造函數(shù)進(jìn)行同步,確保實(shí)例化過程中的線程安全;

(3)對(duì)靜態(tài)變量和方法的訪問和修改,例如在多線程情況下對(duì)靜態(tài)變量進(jìn)行同步。

以下是使用Java編寫一個(gè)演示synchronized關(guān)鍵字的簡單示例:

public class SynchronizedDemo {
    private int counter = 0;
    public synchronized void increment() {
        counter++;
    }
    public synchronized int getCounter() {
        return counter;
    }
    public static void main(String[] args) throws InterruptedException {
        SynchronizedDemo demo = new SynchronizedDemo();
        // create multiple threads to increment counter
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                for (int j = 0; j < 1000; j++) {
                    demo.increment();
                }
            }).start();
        }
        // wait for all threads to finish
        Thread.sleep(5000);
        // print the final value of counter
        System.out.println("Final value of counter: " + demo.getCounter());
    }
}

在上述示例中,我們創(chuàng)建了一個(gè)名為SynchronizedDemo的類,并聲明了一個(gè)私有變量counter。我們?cè)趇ncrement()方法和getCounter()方法上加了synchronized關(guān)鍵字來確保每次只有一個(gè)線程可以訪問這些方法。

在main()方法中,我們創(chuàng)建了10個(gè)線程來并發(fā)地執(zhí)行increment()方法,每個(gè)線程將計(jì)數(shù)器增加1000次。由于increment()方法是同步的,因此在任何時(shí)候都只有一個(gè)線程可以訪問它,從而避免了數(shù)據(jù)競(jìng)爭(zhēng)和不一致性。

最后,我們等待所有線程完成后打印計(jì)數(shù)器的最終值。由于getCounter()方法也是同步的,所以它返回的值將始終是最新的和正確的。

注意事項(xiàng)

(1)使用Volatile時(shí)需要注意可見性和原子性,不能保證多個(gè)操作的原子性。

(2)使用Synchronized時(shí)需要注意同步塊的范圍和對(duì)象的鎖定,避免死鎖和性能問題。

(3)在多線程編程中,需要根據(jù)實(shí)際情況選擇合適的同步機(jī)制或使用多種同步機(jī)制的組合,以保證程序的正確性和可靠性。

相關(guān)面試問題

  • volatile 和 synchronized 有什么區(qū)別?

答:volatile 關(guān)鍵字只能保證變量的可見性,不能保證原子性以及同步性,而 synchronized 關(guān)鍵字既能保證原子性和同步性,也能保證變量的可見性。

  • volatile 能否替代 synchronized?

答:不能。雖然 volatile 可以保證變量的可見性,但是它無法保證原子性和同步性,而 synchronized 能夠保證這三種特性。

  • synchronized 與 volatile 的實(shí)現(xiàn)機(jī)制有何不同?

答:synchronized 是通過對(duì)對(duì)象或類進(jìn)行加鎖來保證同步性和原子性的,其效率相對(duì)較低;而 volatile 是通過禁止 CPU 緩存優(yōu)化來保證變量的可見性,其開銷相對(duì)較小,但不能保證同步性和原子性。

  • 在什么情況下需要使用 volatile?

答:當(dāng)一個(gè)變量被多個(gè)線程訪問時(shí),可能存在緩存不一致的問題,此時(shí)需要使用 volatile 來保證變量的可見性。

  • synchronized 和 volatile 的適用場(chǎng)景分別是什么?

答:synchronized 適用于保證臨界區(qū)代碼的原子性和同步性,而 volatile 適用于保證變量的可見性。因此,如果需要進(jìn)行復(fù)雜的操作并且需要保證原子性和同步性時(shí),應(yīng)該使用 synchronized;而如果只需要保證變量的可見性時(shí),可以使用 volatile。

以上就是java多線程編程必備volatile與synchronized深入理解的詳細(xì)內(nèi)容,更多關(guān)于java多線程volatile synchronized的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 詳解Java中的有參構(gòu)造方法與無參構(gòu)造方法

    詳解Java中的有參構(gòu)造方法與無參構(gòu)造方法

    這篇文章主要詳細(xì)介紹了Java中有參構(gòu)造方法與無參構(gòu)造方法,文中有詳細(xì)的代碼示例,讓大家清晰明了的了解到有參構(gòu)造方法與無參構(gòu)造方法、以及應(yīng)用,需要的朋友可以參考下
    2023-06-06
  • mybatis 事務(wù)回滾配置操作

    mybatis 事務(wù)回滾配置操作

    這篇文章主要介紹了mybatis 事務(wù)回滾配置操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • 詳解JAVA 抽象類

    詳解JAVA 抽象類

    這篇文章主要介紹了JAVA 抽象類的相關(guān)資料,文中講解非常細(xì)致,幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • SpringBoot集成mybatis連接oracle的圖文教程

    SpringBoot集成mybatis連接oracle的圖文教程

    這篇文章主要介紹了Spring Boot集成mybatis連接oracle的圖文教程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • Java文本編輯器實(shí)現(xiàn)方法詳解

    Java文本編輯器實(shí)現(xiàn)方法詳解

    這篇文章主要介紹了Java文本編輯器實(shí)現(xiàn)方法,結(jié)合實(shí)例形式詳細(xì)分析了java文本編輯器結(jié)構(gòu)、原理、布局、實(shí)現(xiàn)步驟與相關(guān)操作技巧,需要的朋友可以參考下
    2019-03-03
  • java實(shí)現(xiàn)把對(duì)象數(shù)組通過excel方式導(dǎo)出的功能

    java實(shí)現(xiàn)把對(duì)象數(shù)組通過excel方式導(dǎo)出的功能

    本文主要介紹了java實(shí)現(xiàn)把對(duì)象數(shù)組通過excel方式導(dǎo)出的功能的相關(guān)知識(shí)。具有很好的參考價(jià)值,下面跟著小編一起來看下吧
    2017-03-03
  • java中基本注解的知識(shí)點(diǎn)總結(jié)

    java中基本注解的知識(shí)點(diǎn)總結(jié)

    在本篇文章里小編給大家整理的是一篇關(guān)于java中基本注解的知識(shí)點(diǎn)總結(jié),有需要的朋友們可以跟著學(xué)習(xí)下。
    2021-06-06
  • Java Integer及int裝箱拆箱對(duì)比

    Java Integer及int裝箱拆箱對(duì)比

    這篇文章主要介紹了Java Integer及int裝箱拆箱對(duì)比,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-09-09
  • Java 字符串壓縮與解壓的開發(fā)記錄

    Java 字符串壓縮與解壓的開發(fā)記錄

    這篇文章主要介紹了Java 字符串壓縮與解壓的開發(fā)記錄,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-06-06
  • SpringCloud?hystrix斷路器與全局解耦全面介紹

    SpringCloud?hystrix斷路器與全局解耦全面介紹

    什么是服務(wù)降級(jí)?當(dāng)服務(wù)器壓力劇增的情況下,根據(jù)實(shí)際業(yè)務(wù)情況及流量,對(duì)一些服務(wù)和頁面有策略的不處理或換種簡單的方式處理,從而釋放服務(wù)器資源以保證核心交易正常運(yùn)作或高效運(yùn)作
    2022-10-10

最新評(píng)論