国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

JavaEE 初階篇-深入了解多線程安全問題(指令重排序、解決內(nèi)存可見性與等待通知機(jī)制)

這篇具有很好參考價(jià)值的文章主要介紹了JavaEE 初階篇-深入了解多線程安全問題(指令重排序、解決內(nèi)存可見性與等待通知機(jī)制)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

??博客主頁(yè):?【小扳_-CSDN博客】
?感謝大家點(diǎn)贊??收藏?評(píng)論?

JavaEE 初階篇-深入了解多線程安全問題(指令重排序、解決內(nèi)存可見性與等待通知機(jī)制),JavaEE 初級(jí)篇,java,開發(fā)語(yǔ)言,java-ee

JavaEE 初階篇-深入了解多線程安全問題(指令重排序、解決內(nèi)存可見性與等待通知機(jī)制),JavaEE 初級(jí)篇,java,開發(fā)語(yǔ)言,java-ee

文章目錄

? ? ? ? 1.0 指令重排序概述

? ? ? ? 1.1 指令重排序主要分為兩種類型

? ? ? ? 1.2 指令重排序所引發(fā)的問題

? ? ? ? 2.0 內(nèi)存可見性概述

? ? ? ? 2.1 導(dǎo)致內(nèi)存可見性問題主要涉及兩個(gè)方面

? ? ? ? 2.2 解決內(nèi)存可見性問題

? ? ? ? 2.2.1 使用 volatile 關(guān)鍵字

? ? ? ? 2.2.2 使用 synchronized 關(guān)鍵字

? ? ? ? 3.0 線程的等待通知機(jī)制概述

? ? ? ? 3.1 等待 - wait()

? ? ? ? 3.2 通知 - notity()

? ? ? ? 3.3 通知所有 - notifyAll()


? ? ? ? 1.0 指令重排序概述

????????指令重排序是指編譯器或處理器為了提高性能,在不改變程序執(zhí)行結(jié)果的前提下,可以對(duì)指令序列進(jìn)行重新排序的優(yōu)化技術(shù)。這種優(yōu)化技術(shù)可以使得計(jì)算機(jī)在執(zhí)行指令時(shí)更高效地利用計(jì)算資源,提高程序的執(zhí)行效率。

? ? ? ? 1.1 指令重排序主要分為兩種類型

? ? ? ? 1)編譯器重排序:編譯器在生成目標(biāo)代碼時(shí)會(huì)對(duì)源代碼中的指令進(jìn)行優(yōu)化和重排,以提高程序的執(zhí)行效率。編譯器重排序時(shí)在編譯階段完成的,目的是生成更高效率的機(jī)器代碼。

? ? ? ? 2)處理器重排序:處理器在執(zhí)行指令也可以對(duì)指令進(jìn)行重排序,以最大程度地利用處理器的流水線和多核等特性。目的提高指令的執(zhí)行效率。

? ? ? ? 1.2 指令重排序所引發(fā)的問題

? ? ? ? 雖然指令重排序可以提高程序的執(zhí)行效率但是在多線程編程中可能會(huì)引發(fā)內(nèi)存可見性問題。由于指令重排序可能導(dǎo)致共享變量的讀寫順序與代碼中的順序不一致,當(dāng)多個(gè)線程同時(shí)訪問共享變量時(shí),可能會(huì)出現(xiàn)數(shù)據(jù)不一致的情況。

? ? ? ? 2.0 內(nèi)存可見性概述

????????在多線程編程中,由于線程之間的執(zhí)行是并發(fā)的,每個(gè)線程有自己的工作內(nèi)存,共享變量存儲(chǔ)在主內(nèi)存中,線程在執(zhí)行過(guò)程中會(huì)將共享變量從主內(nèi)存中拷貝到自己的工作內(nèi)存中進(jìn)行操作,操作完成后再將結(jié)果寫回主內(nèi)存。這里的工作內(nèi)存指的是:寄存器或者是緩存。

? ? ? ? 2.1 導(dǎo)致內(nèi)存可見性問題主要涉及兩個(gè)方面

? ? ? ? 1)多線程并發(fā)操作搶占式執(zhí)行導(dǎo)致內(nèi)存可見性:如果一個(gè)現(xiàn)車給修改了共享變量的值,但其他線程無(wú)法立即看到這個(gè)修改之后的共享變量,就會(huì)導(dǎo)致數(shù)據(jù)不一致的情況。

? ? ? ? 2)指令重排序?qū)е聝?nèi)存可見性:由于編譯器和處理器可以對(duì)指令進(jìn)行重排序優(yōu)化,可能會(huì)導(dǎo)致共享變量的讀寫順序與代碼中的順序不一致,從而影響了線程對(duì)共享變量的可見性。

代碼如下:

public class demo1 {

    public static int count = 0;
    public static void main(String[] args) {

        Thread t1 = new Thread(()->{
            while (count == 0){

            };
            System.out.println("線程 t1 結(jié)束");
        });

        Thread t2 = new Thread(()->{
            Scanner scanner = new Scanner(System.in);
            System.out.println("輸出:");
            count = scanner.nextInt();
        });

        t1.start();
        t2.start();

    }
}

? ? ? ? t1 在啟動(dòng)線程之后,只要 count == 0 這個(gè)條件滿足時(shí),就會(huì)進(jìn)入循環(huán);t2 啟動(dòng)線程要求輸出一個(gè)值并且將該值賦值給 count 。

????????預(yù)想過(guò)程:只要輸出一個(gè)非 0 的值時(shí),那么 count 不為 0 了,t1 線程中的循環(huán)就會(huì)退出,因此會(huì)輸出 ”線程 t1 結(jié)束“ 這句話。最后程序結(jié)束。

運(yùn)行結(jié)果:

JavaEE 初階篇-深入了解多線程安全問題(指令重排序、解決內(nèi)存可見性與等待通知機(jī)制),JavaEE 初級(jí)篇,java,開發(fā)語(yǔ)言,java-ee

? ? ? ? 輸出 1 之后,按理來(lái)說(shuō),count 此時(shí)應(yīng)該賦值為 1 了,那么 t1 中的循環(huán)應(yīng)該要結(jié)束了并且得輸出一段話。但是,看到結(jié)果,即使輸出了 1 之后,t1 還在循環(huán)中。

原因如下:

? ? ? ? 由于 t1 循環(huán)中的代碼塊里面是沒有任何代碼,無(wú)需任何操作,在 CPU 中主要執(zhí)行兩條指令:load 將內(nèi)存中的 count 加載到寄存器中;cmp 將 count 與 0 之間進(jìn)行比較。

????????因?yàn)?cpm 執(zhí)行這條指令直接在寄存器中操作,而 load 需要將內(nèi)存的數(shù)據(jù)加載到寄存器中,這個(gè)操作的速度就比 cmp 的速度慢很多很多了。所以編譯器重排序在生成目標(biāo)代碼時(shí)對(duì)源代碼中的指令進(jìn)行優(yōu)化重排,將 count 變量存儲(chǔ)到寄存器或者緩存中,目的為了提高執(zhí)行效率。然而,t2 線程對(duì) count 進(jìn)行重新賦值后,將重新賦值后的 count 寫回到主存中,但是 t1 線程是沒有看到重新賦值后的 count 變量。因?yàn)閷?duì)于 t1 線程來(lái)說(shuō),count 變量已經(jīng)”固定“在工作內(nèi)存中,沒有重新加載主存中的 count 變量,而是反復(fù)讀取自己工作內(nèi)存中的 count == 0 這個(gè)變量。

? ? ? ? 總而言之,指令重排序?qū)е铝藘?nèi)存可見性問題。

? ? ? ? 2.2 解決內(nèi)存可見性問題

? ? ? ? 主要有兩個(gè)方法:使用 volatile 關(guān)鍵字、使用 synchronized 關(guān)鍵字。

? ? ? ? 2.2.1 使用 volatile 關(guān)鍵字

? ? ? ? volatile 關(guān)鍵字可以確保被修飾的變量對(duì)所有線程可見,禁止指令重排序。

代碼如下:

當(dāng)給 count 加上 volatile 關(guān)鍵時(shí),編譯器或者處理器就不會(huì)對(duì)指令重排序了

import java.util.Scanner;

public class demo1 {

    public static volatile int count = 0;
    public static void main(String[] args) {

        Thread t1 = new Thread(()->{
            while (count == 0){

            };
            System.out.println("線程 t1 結(jié)束");
        });

        Thread t2 = new Thread(()->{
            Scanner scanner = new Scanner(System.in);
            System.out.println("輸出:");
            count = scanner.nextInt();
        });

        t1.start();
        t2.start();

    }
}

運(yùn)行結(jié)果:

JavaEE 初階篇-深入了解多線程安全問題(指令重排序、解決內(nèi)存可見性與等待通知機(jī)制),JavaEE 初級(jí)篇,java,開發(fā)語(yǔ)言,java-ee

? ? ? ? 當(dāng)輸出 1 回車之后,count 就會(huì)重新賦值為 1 。從而 t1 中的循環(huán)退出,輸出打印之后,整個(gè)進(jìn)程就結(jié)束了。

? ? ? ? 2.2.2 使用 synchronized 關(guān)鍵字

? ? ? ? 可以確保同一時(shí)刻只有一個(gè)線程可以訪問共享變量,同時(shí)保證了線程間的數(shù)據(jù)一致性。

代碼如下:

import java.util.Scanner;

public class demo1 {

    public static int count = 0;
    public static void main(String[] args) {
    Object o = new Object();
        Thread t1 = new Thread(()->{
            synchronized (o){
                System.out.println("線程 t1 開始");
                while (count == 0){
                    try {
                        o.wait();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }

                };

                System.out.println("線程 t1 結(jié)束");
            }
        });

        Thread t2 = new Thread(()->{
                System.out.println("輸出:");
                Scanner scanner = new Scanner(System.in);
                synchronized (o){
                    count = scanner.nextInt();
                    o.notify();
                }
        });

        t1.start();
        t2.start();

    }
}

運(yùn)行結(jié)果:

JavaEE 初階篇-深入了解多線程安全問題(指令重排序、解決內(nèi)存可見性與等待通知機(jī)制),JavaEE 初級(jí)篇,java,開發(fā)語(yǔ)言,java-ee

????????t1 線程在進(jìn)入循環(huán)前會(huì)先獲取對(duì)象 o 的鎖,并在循環(huán)體中通過(guò) o.wait() 釋放鎖并等待喚醒。當(dāng) t2 線程修改了 count 的值后,會(huì)再次獲取對(duì)象 o 的鎖并調(diào)用 o.notify() 喚醒 t1 線程,從而解除等待狀態(tài),保證了內(nèi)存可見性和線程間的通信。

????????

? ? ? ? 3.0 線程的等待通知機(jī)制概述

????????線程的等待通知機(jī)制是多線程編程中常用的一種同步機(jī)制,用于實(shí)現(xiàn)線程間的協(xié)作和通信。

? ? ? ? 3.1 等待 - wait()

? ? ? ? 線程調(diào)用對(duì)象的 wait() 方法時(shí),會(huì)釋放對(duì)象的鎖并且同時(shí)進(jìn)入等待狀態(tài),直到其他線程調(diào)用相同對(duì)象的 notify() 或者 notifyAll() 方法來(lái)喚醒它。在等待的過(guò)程中,線程會(huì)一直處于阻塞狀態(tài)。?

? ? ? ? 3.2 通知 - notity()

? ? ? ? 線程調(diào)用對(duì)象的 notify() 方法時(shí),會(huì)喚醒等待在該對(duì)象上的一個(gè)線程,若有多個(gè)等待喚醒的線程時(shí),具體喚醒的線程是不確定的,使其從等待狀態(tài)轉(zhuǎn)為就緒狀態(tài),被喚醒的線程會(huì)嘗試重新獲取對(duì)象的鎖,并繼續(xù)執(zhí)行。

? ? ? ? 3.3 通知所有 - notifyAll()

? ? ? ? 線程調(diào)用對(duì)象的 notifyAll() 方法時(shí),會(huì)喚醒所有等待在該對(duì)象上的線程,使它們從等待狀態(tài)轉(zhuǎn)為就緒狀態(tài)。被喚醒的線程會(huì)競(jìng)爭(zhēng)對(duì)象的鎖,只有一個(gè)線程能夠獲取鎖并繼續(xù)執(zhí)行,其他線程會(huì)再次進(jìn)入等待狀態(tài)。

舉個(gè)例子:

public class demo2 {
    public static void main(String[] args) throws InterruptedException {
        Object lock = new Object();
        Thread t1 = new Thread(()->{
            synchronized (lock){
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println("正在執(zhí)行 t1 線程");
            }
        });
        Thread t2 = new Thread(()->{
            synchronized (lock){
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println("正在執(zhí)行 t2 線程");
            }
        });
        Thread t3 = new Thread(()->{
            synchronized (lock){
                lock.notify();
                lock.notify();
                System.out.println("正在執(zhí)行 t3 線程");
            }
        });
        t1.start();
        t2.start();
        Thread.sleep(1000);
        t3.start();
    }
}

? ? ? ? t1 ,t2 線程都在阻塞狀態(tài),等待 t3 線程通知,但是 t3 線程還沒釋放鎖,所以 t1 ,t2 線程繼續(xù)阻塞狀態(tài)。直到 t3 線程釋放鎖之后,t1,t2 線程就可以競(jìng)爭(zhēng)獲取鎖,假設(shè) t1 獲取鎖之后,執(zhí)行完代碼,釋放鎖,t1 線程結(jié)束。再到 t2 線程獲取鎖,執(zhí)行完代碼釋放鎖,t2 線程也結(jié)束。因此線程的先后順序:t3 線程一定是最早結(jié)束的,接著到 t1 或者 t2 線程隨機(jī)其中的一個(gè)線程。

運(yùn)行結(jié)果:

JavaEE 初階篇-深入了解多線程安全問題(指令重排序、解決內(nèi)存可見性與等待通知機(jī)制),JavaEE 初級(jí)篇,java,開發(fā)語(yǔ)言,java-ee

補(bǔ)充:

????????等待通知機(jī)制通常需要搭配 synchronized 關(guān)鍵字來(lái)確保線程安全。在Java中, wait()、notiyf() 和 notiyfAll() 方法必須在同步代碼塊或同步方法中調(diào)用,即在獲取對(duì)象鎖的情況下使用,以避免出現(xiàn)并發(fā)訪問的問題。

JavaEE 初階篇-深入了解多線程安全問題(指令重排序、解決內(nèi)存可見性與等待通知機(jī)制),JavaEE 初級(jí)篇,java,開發(fā)語(yǔ)言,java-ee文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-851794.html

到了這里,關(guān)于JavaEE 初階篇-深入了解多線程安全問題(指令重排序、解決內(nèi)存可見性與等待通知機(jī)制)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • JavaEE 初階篇-深入了解 I/O 高級(jí)流(緩沖流、交換流、數(shù)據(jù)流和序列化流)

    JavaEE 初階篇-深入了解 I/O 高級(jí)流(緩沖流、交換流、數(shù)據(jù)流和序列化流)

    ??博客主頁(yè):?【 小扳_-CSDN博客】 ?感謝大家點(diǎn)贊??收藏?評(píng)論? 文章目錄 ? ? ? ? 1.0 緩沖流概述 ? ? ? ? 1.1 緩沖流的工作原理 ? ? ? ? 1.2 使用緩沖流的步驟 ? ? ? ? 1.3?字節(jié)緩沖流于字符緩沖流的區(qū)別 ? ? ? ? 1.4?字節(jié)緩沖流的實(shí)例 ? ? ? ? 1.5?字符緩沖流的實(shí)例

    2024年04月29日
    瀏覽(20)
  • JavaEE 初階篇-線程安全的集合類、多線程環(huán)境使用 ArrayList、隊(duì)列、哈希表(HashMap 、ConCurrentHashMap 、HashTable 的區(qū)別)

    JavaEE 初階篇-線程安全的集合類、多線程環(huán)境使用 ArrayList、隊(duì)列、哈希表(HashMap 、ConCurrentHashMap 、HashTable 的區(qū)別)

    ??博客主頁(yè):?【 小扳_-CSDN博客】 ?感謝大家點(diǎn)贊??收藏?評(píng)論? ? 文章目錄 ? ? ? ? 1.0 線程安全的集合類 ? ? ? ? 1.2?線程安全的集合類 - Vector ? ? ? ? 1.3 線程安全的集合類 - Stack ? ? ? ? 1.4 線程安全的集合類 - HashTable ? ? ? ? 2.0 多線程環(huán)境使用 ArrayList ? ? ? ?

    2024年04月25日
    瀏覽(59)
  • JavaEE 初階篇-生產(chǎn)者與消費(fèi)者模型(線程通信)

    JavaEE 初階篇-生產(chǎn)者與消費(fèi)者模型(線程通信)

    ??博客主頁(yè):?【 小扳_-CSDN博客】 ?感謝大家點(diǎn)贊??收藏?評(píng)論? ? 文章目錄 ? ? ? ? 1.0 生產(chǎn)者與消費(fèi)者模型概述 ? ? ? ? 2.0?在生產(chǎn)者與消費(fèi)者模型中涉及的關(guān)鍵概念 ? ? ? ? 2.1 緩沖區(qū) ? ? ? ? 2.2 生產(chǎn)者 ? ? ? ? 2.3 消費(fèi)者 ? ? ? ? 2.4 同步機(jī)制 ? ? ? ? 2.5 線程間通

    2024年04月28日
    瀏覽(31)
  • JavaEE 初階篇-深入了解 CAS 機(jī)制與12種鎖的特征(如樂觀鎖和悲觀鎖、輕量級(jí)鎖與重量級(jí)鎖、自旋鎖與掛起等待鎖、可重入鎖與不可重入鎖等等)

    JavaEE 初階篇-深入了解 CAS 機(jī)制與12種鎖的特征(如樂觀鎖和悲觀鎖、輕量級(jí)鎖與重量級(jí)鎖、自旋鎖與掛起等待鎖、可重入鎖與不可重入鎖等等)

    ??博客主頁(yè):?【 小扳_-CSDN博客】 ?感謝大家點(diǎn)贊??收藏?評(píng)論? 文章目錄 ? ? ? ? 1.0 樂觀鎖與悲觀鎖概述 ? ? ? ? 1.1 悲觀鎖(Pessimistic Locking) ? ? ? ? 1.2 樂觀鎖(Optimistic Locking) ? ? ? ? 1.3 區(qū)別與適用場(chǎng)景 ? ? ? ? 2.0 輕量級(jí)鎖與重量級(jí)鎖概述 ? ? ? ? 2.1 真正加

    2024年04月16日
    瀏覽(40)
  • 【JavaEE】并發(fā)編程(多線程)線程安全問題&內(nèi)存可見性&指令重排序

    【JavaEE】并發(fā)編程(多線程)線程安全問題&內(nèi)存可見性&指令重排序

    目錄 第一個(gè)問題:什么是線程安全問題? 第二個(gè)問題:為什么會(huì)出現(xiàn)線程安全問題?? 第三個(gè)問題:如何解決多線程安全問題?? 第四個(gè)問題:產(chǎn)生線程不安全的原因有哪些?? 第五個(gè)問題:內(nèi)存可見性問題及解決方案? 第六個(gè)問題:指令重排序問題? 線程安全就是多線程

    2024年02月01日
    瀏覽(25)
  • 【JavaEE初階】 線程安全

    【JavaEE初階】 線程安全

    線程安全是多線程編程是的計(jì)算機(jī)程序代碼中的一個(gè)概念。在擁有共享數(shù)據(jù)的多條線程并行執(zhí)行的程序中,線程安全的代碼會(huì)通過(guò)同步機(jī)制保證各個(gè)線程都可以正常且準(zhǔn)確的執(zhí)行,不會(huì)出現(xiàn)數(shù)據(jù)污染等意外情況。上述是百度百科給出的一個(gè)概念解釋。換言之,線程安全就是某

    2024年02月08日
    瀏覽(24)
  • 【JavaEE初階】 線程安全的集合類

    【JavaEE初階】 線程安全的集合類

    原來(lái)的集合類, 大部分都不是線程安全的. Vector, Stack, HashTable, 是線程安全的(不建議用), 其他的集合類不是線程安全的. 為什么不建議使用呢? 因?yàn)槲覀冊(cè)谑褂玫臅r(shí)候,這些類就會(huì)自動(dòng)的加鎖,雖然編譯器會(huì)自動(dòng)優(yōu)化為沒有鎖競(jìng)爭(zhēng)的線程進(jìn)行鎖消除的優(yōu)化,但是呢萬(wàn)一編譯器沒

    2024年02月08日
    瀏覽(58)
  • javaEE初階——多線程(九)——JUC常見的類以及線程安全的集合類

    javaEE初階——多線程(九)——JUC常見的類以及線程安全的集合類

    T04BF ??專欄: 算法|JAVA|MySQL|C語(yǔ)言 ?? 小比特 大夢(mèng)想 此篇文章與大家分享多線程專題的最后一篇文章:關(guān)于JUC常見的類以及線程安全的集合類 如果有不足的或者錯(cuò)誤的請(qǐng)您指出! 3.1Callable接口 Callable和Runnable一樣,都是用來(lái)描述一個(gè)任務(wù)的 但是區(qū)別在于 ,用Callable描述的任務(wù)是有

    2024年04月25日
    瀏覽(21)
  • 【JavaEE】多線程之線程安全(synchronized篇),死鎖問題

    【JavaEE】多線程之線程安全(synchronized篇),死鎖問題

    線程安全問題 觀察線程不安全 線程安全問題的原因? 從原子性入手解決線程安全問題?——synchronized synchronized的使用方法? synchronized的互斥性和可重入性 死鎖 死鎖的三個(gè)典型情況? 死鎖的四個(gè)必要條件? 破除死鎖 在前面的章節(jié)中,我們也了解到多線程為我們的程序帶來(lái)了

    2024年02月01日
    瀏覽(25)
  • 【JavaEE初階】了解JVM

    【JavaEE初階】了解JVM

    JVM啟動(dòng)的時(shí)候,會(huì)申請(qǐng)到一整個(gè)很大的內(nèi)存區(qū)域.JVM是一個(gè)應(yīng)用程序,要從操作系統(tǒng)里申請(qǐng)內(nèi)存.JVM就根據(jù)需要,把空間分為幾個(gè)部分,每個(gè)部分各自有不同的功能.具體劃分如下: Native Method Stacks(本地方法棧) :native表示是JVM內(nèi)部的C++代碼.就是給調(diào)用native方法(JVM內(nèi)部的方法)準(zhǔn)備的棧空

    2024年02月13日
    瀏覽(24)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包