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

Java內(nèi)存模型JMM深入解析

 更新時(shí)間:2025年12月17日 11:57:12   作者:rchmin  
JMM(Java內(nèi)存模型)規(guī)范了多線程環(huán)境下Java程序中變量的內(nèi)存訪問規(guī)則,解決了可見性、原子性和有序性問題,通過關(guān)鍵字和規(guī)則確保多線程程序的正確性和線程安全性,本文介紹Java內(nèi)存模型JMM的相關(guān)知識(shí),感興趣的朋友一起看看吧

1. 什么是 JMM?

JMM 的全稱是 Java Memory Model,即 Java 內(nèi)存模型。

簡單來說,JMM 是一套規(guī)范,它定義了在多線程環(huán)境下,Java 程序中的變量(特別是共享變量)如何被寫入內(nèi)存以及如何從內(nèi)存中讀取的規(guī)則。

關(guān)鍵點(diǎn):

  • 它不是 指 Java 程序運(yùn)行時(shí)內(nèi)存區(qū)域的劃分(如堆、棧、方法區(qū))。那是 JVM 內(nèi)存結(jié)構(gòu),是兩個(gè)不同的概念。
  • 它是 一個(gè)抽象的概念,是一組規(guī)則和規(guī)范,旨在解決由于多線程訪問共享數(shù)據(jù)而可能引發(fā)的各種問題,如內(nèi)存可見性、原子性、有序性等。

2. 為什么需要 JMM?(JMM 要解決的問題)

在沒有 JMM 約束的情況下,多線程編程會(huì)面臨三大核心難題,這主要是由于現(xiàn)代計(jì)算機(jī)架構(gòu)(如多級(jí)緩存、CPU 指令重排序)造成的。

1. 可見性

  • 問題: 一個(gè)線程修改了共享變量的值,另一個(gè)線程不能立即看到這個(gè)修改。
  • 原因: 為了提高效率,每個(gè)線程都有自己的工作內(nèi)存(可以理解為CPU高速緩存的一個(gè)抽象),它們會(huì)先將主內(nèi)存中的共享變量拷貝一份到自己的工作內(nèi)存中進(jìn)行操作,操作完成后并不一定會(huì)立即寫回主內(nèi)存。如果線程A修改了值但未刷新到主內(nèi)存,線程B讀取到的就還是舊的值。
  • 例子:
// 共享變量
private static boolean flag = false;
public static void main(String[] args) {
    new Thread(() -> {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        flag = true; // 線程A修改flag為true
        System.out.println("Flag set to true.");
    }).start();
    new Thread(() -> {
        while (!flag) { 
            // 線程B可能永遠(yuǎn)無法跳出循環(huán),因?yàn)樗床坏骄€程A對flag的修改
        }
        System.out.println("Thread sees flag change.");
    }).start();
}

在沒有同步措施的情況下,第二個(gè)線程可能會(huì)陷入死循環(huán)。

2. 原子性

  • 問題: 一個(gè)或多個(gè)操作,要么全部執(zhí)行成功,要么全部不執(zhí)行,中間不能被任何其他操作中斷。
  • 原因: 即使是看似簡單的操作(如 i++),在底層也是由多個(gè)指令組成的(讀取 i,計(jì)算 i+1,寫回 i)。如果多個(gè)線程同時(shí)執(zhí)行 i++,就可能發(fā)生線程A剛讀取完 i 的值,CPU時(shí)間片就被線程B搶走,線程B也讀取了相同的值并完成寫入,然后線程A再繼續(xù)寫回,最終導(dǎo)致兩次 i++ 結(jié)果只增加了1。
  • 例子: count++ 就不是原子操作。

3. 有序性

  • 問題: 程序執(zhí)行的順序不一定就是代碼編寫的順序。
  • 原因: 為了性能優(yōu)化,編譯器和處理器常常會(huì)對指令進(jìn)行重排序。只要在單線程環(huán)境下,重排序后的結(jié)果與順序執(zhí)行的結(jié)果一致(遵守 as-if-serial 語義),這種優(yōu)化就是被允許的。但在多線程環(huán)境下,重排序可能會(huì)導(dǎo)致意想不到的結(jié)果。
  • 例子(經(jīng)典的雙重檢查鎖定單例模式問題):
public class Singleton {
    private static Singleton instance; // 沒有volatile
    public static Singleton getInstance() {
        if (instance == null) { // 第一次檢查
            synchronized (Singleton.class) {
                if (instance == null) { // 第二次檢查
                    instance = new Singleton(); // 非原子操作,可能發(fā)生重排序
                }
            }
        }
        return instance;
    }
}

instance = new Singleton() 這行代碼在 JVM 中大致做了三件事:

  • 分配對象的內(nèi)存空間
  • 初始化對象
  • 將 instance 引用指向這塊內(nèi)存
  • 如果步驟2和3被重排序,線程A可能剛執(zhí)行完步驟3(instance 已不為null)但還未初始化對象時(shí),線程B在第一次檢查 if (instance == null) 時(shí)發(fā)現(xiàn)不為null,就會(huì)直接返回一個(gè)尚未初始化完成的錯(cuò)誤對象。

3. JMM 是如何解決這些問題的?

JMM 通過定義一些關(guān)鍵的 關(guān)鍵字 和 規(guī)則 來解決上述問題,主要是圍繞 主內(nèi)存 和 工作內(nèi)存 之間的交互協(xié)議。

核心手段:

  • synchronized 關(guān)鍵字
    • 原子性: synchronized 塊中的操作具有原子性,同一時(shí)刻只有一個(gè)線程能執(zhí)行。
    • 可見性: 當(dāng)線程進(jìn)入 synchronized 塊時(shí),會(huì)清空工作內(nèi)存,從主內(nèi)存重新加載變量。退出 synchronized 塊時(shí),會(huì)把工作內(nèi)存中的修改刷新到主內(nèi)存。
    • 有序性: 它通過“一個(gè)變量在同一時(shí)刻只允許一條線程對其進(jìn)行 lock 操作”來限制重排序,從而保證有序性??梢钥醋魇菃尉€程執(zhí)行。
  • volatile 關(guān)鍵字
    • 可見性: 當(dāng)寫一個(gè) volatile 變量時(shí),JMM 會(huì)立即將該線程工作內(nèi)存中的新值強(qiáng)制刷新到主內(nèi)存。當(dāng)讀一個(gè) volatile 變量時(shí),JMM 會(huì)使該線程的工作內(nèi)存無效,從而從主內(nèi)存中重新讀取。
    • 有序性: 它通過插入內(nèi)存屏障 來禁止指令重排序。確保了 volatile 寫操作之前的任何讀寫操作都不會(huì)被重排序到寫操作之后;volatile 讀操作之后的任何讀寫操作都不會(huì)被重排序到讀操作之前。
    • 注意: volatile 不保證原子性(例如 volatile int i; i++ 仍然不是原子的)。
  • Happens-Before 原則
    • 這是 JMM 中最核心、最復(fù)雜的概念之一。它是一組規(guī)則,用于描述兩個(gè)操作之間的內(nèi)存可見性。如果操作 A Happens-Before 于操作 B,那么 A 操作所做的任何修改對 B 操作都是可見的。
  • 程序次序規(guī)則: 在一個(gè)線程內(nèi),書寫在前面的操作先行發(fā)生于書寫在后面的操作。
  • 管程鎖定規(guī)則: 一個(gè) unlock 操作先行發(fā)生于后面對同一個(gè)鎖的 lock 操作。
  • volatile變量規(guī)則: 對一個(gè) volatile 變量的寫操作先行發(fā)生于后面對這個(gè)變量的讀操作。
  • 線程啟動(dòng)規(guī)則: Thread 對象的 start() 方法先行發(fā)生于此線程的每一個(gè)動(dòng)作。
  • 線程終止規(guī)則: 線程中的所有操作都先行發(fā)生于對此線程的終止檢測。
  • 線程中斷規(guī)則: 對線程 interrupt() 方法的調(diào)用先行發(fā)生于被中斷線程的代碼檢測到中斷事件的發(fā)生。
  • 對象終結(jié)規(guī)則: 一個(gè)對象的初始化完成先行發(fā)生于它的 finalize() 方法的開始。
  • 傳遞性: 如果操作 A 先行發(fā)生于操作 B,操作 B 先行發(fā)生于操作 C,那么操作 A 先行發(fā)生于操作 C。

總結(jié)

特性問題描述JMM 解決方案
原子性操作被中途打斷synchronized
可見性一個(gè)線程的修改對其他線程不可見synchronizedvolatile, Happens-Before
有序性指令執(zhí)行順序與代碼順序不一致synchronizedvolatile, Happens-Before

一句話總結(jié):
JMM(Java內(nèi)存模型)是一套規(guī)范,它屏蔽了底層硬件內(nèi)存訪問的差異,為 Java 開發(fā)者提供了一套統(tǒng)一的內(nèi)存訪問模型,使得我們在編寫多線程程序時(shí),即使在不了解底層硬件細(xì)節(jié)的情況下,也能通過使用 synchronized、volatile 等關(guān)鍵字,編寫出正確、線程安全的代碼。

到此這篇關(guān)于Java內(nèi)存模型JMM深入解析的文章就介紹到這了,更多相關(guān)Java內(nèi)存模型JMM內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Nacos配置中心與本地代碼工程配置文件之間的優(yōu)先級(jí)關(guān)系詳解

    Nacos配置中心與本地代碼工程配置文件之間的優(yōu)先級(jí)關(guān)系詳解

    本文介紹了Spring Cloud生態(tài)中配置加載原理,強(qiáng)調(diào)Nacos遠(yuǎn)程配置優(yōu)先級(jí)高于本地`application.yml`但低于命令行和環(huán)境變量,覆蓋了多環(huán)境配置、動(dòng)態(tài)刷新配置及安全配置外置等應(yīng)用場景,對比了Nacos配置中心與本地配置文件的優(yōu)缺點(diǎn),并給出最佳實(shí)踐建議
    2026-04-04
  • Java中Spring獲取bean方法小結(jié)

    Java中Spring獲取bean方法小結(jié)

    Spring是一個(gè)輕量級(jí)的控制反轉(zhuǎn)(IoC)和面向切面(AOP)的容器框架,如何在程序中獲取Spring配置的bean呢?下面通過本文給大家介紹Java中Spring獲取bean方法小結(jié),對spring獲取bean方法相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)吧
    2016-01-01
  • 劍指Offer之Java算法習(xí)題精講數(shù)組與列表的查找及字符串轉(zhuǎn)換

    劍指Offer之Java算法習(xí)題精講數(shù)組與列表的查找及字符串轉(zhuǎn)換

    跟著思路走,之后從簡單題入手,反復(fù)去看,做過之后可能會(huì)忘記,之后再做一次,記不住就反復(fù)做,反復(fù)尋求思路和規(guī)律,慢慢積累就會(huì)發(fā)現(xiàn)質(zhì)的變化
    2022-03-03
  • Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(59)

    Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(59)

    下面小編就為大家?guī)硪黄狫ava基礎(chǔ)的幾道練習(xí)題(分享)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧,希望可以幫到你
    2021-08-08
  • Java實(shí)現(xiàn)壓縮圖片大小

    Java實(shí)現(xiàn)壓縮圖片大小

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)壓縮圖片大小,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • 解讀Spring-boot的debug調(diào)試

    解讀Spring-boot的debug調(diào)試

    這篇文章主要介紹了解讀Spring-boot的debug調(diào)試,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • SpringMVC 通過ajax 實(shí)現(xiàn)文件上傳的步驟

    SpringMVC 通過ajax 實(shí)現(xiàn)文件上傳的步驟

    使用form表單在springmvc 項(xiàng)目中上傳文件,文件上傳成功之后往往會(huì)跳轉(zhuǎn)到其他的頁面,但是有的時(shí)候,文件上傳成功的同時(shí),并不需要進(jìn)行頁面的跳轉(zhuǎn),可以通過ajax來實(shí)現(xiàn)文件的上傳,下面給大家介紹SpringMVC 通過ajax 實(shí)現(xiàn)文件上傳的步驟,感興趣的朋友一起看看吧
    2025-05-05
  • 學(xué)習(xí)不同 Java.net 語言中類似的函數(shù)結(jié)構(gòu)

    學(xué)習(xí)不同 Java.net 語言中類似的函數(shù)結(jié)構(gòu)

    這篇文章主要介紹了學(xué)習(xí)不同 Java.net 語言中類似的函數(shù)結(jié)構(gòu),函數(shù)式編程語言包含多個(gè)系列的常見函數(shù)。但開發(fā)人員有時(shí)很難在語言之間進(jìn)行切換,因?yàn)槭煜さ暮瘮?shù)具有不熟悉的名稱。函數(shù)式語言傾向于基于函數(shù)范例來命名這些常見函數(shù)。,需要的朋友可以參考下
    2019-06-06
  • spring整合kaptcha驗(yàn)證碼的實(shí)現(xiàn)

    spring整合kaptcha驗(yàn)證碼的實(shí)現(xiàn)

    這篇文章主要介紹了spring整合kaptcha驗(yàn)證碼的實(shí)現(xiàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-05-05
  • SpringBoot Redis批量存取數(shù)據(jù)的操作

    SpringBoot Redis批量存取數(shù)據(jù)的操作

    這篇文章主要介紹了SpringBoot Redis批量存取數(shù)據(jù)的操作,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08

最新評論

曲靖市| 宁南县| 客服| 许昌市| 沾益县| 洪江市| 麻栗坡县| 阿拉善盟| 保山市| 南昌县| 宁蒗| 油尖旺区| 弥勒县| 永平县| 奈曼旗| 凤城市| 延边| 哈巴河县| 扶风县| 新蔡县| 闽侯县| 介休市| 邵武市| 沙田区| 宁波市| 伊宁县| 锡林郭勒盟| 中山市| 肇州县| 普兰县| 和政县| 高阳县| 阳江市| 四平市| 兴城市| 长汀县| 来宾市| 伊春市| 丹东市| 宁化县| 吴江市|