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

一篇文章深入聊聊Java的內(nèi)存模型

 更新時(shí)間:2026年02月03日 09:29:02   作者:曄子yy  
這篇文章主要介紹了Java內(nèi)存模型的相關(guān)資料,JMM是Java內(nèi)存模型,它本身只是一個(gè)抽象的概念,并不真實(shí)存在,它描述的是一種規(guī)則或規(guī)范,是和多線程相關(guān)的一組規(guī)范,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下

1、Java的內(nèi)存模型(JMM)介紹

JMM核心定義和作用

Java內(nèi)存模型(Java Memory Model,JMM)是Java虛擬機(jī)規(guī)范中定義的一種抽象概念,它規(guī)定了多線程環(huán)境下,線程如何與內(nèi)存進(jìn)行交互。

JMM的核心作用:

  • 定義程序中各個(gè)變量的訪問規(guī)則

  • 確保多線程程序的可見性、有序性原子性

  • 屏蔽不同硬件平臺(tái)和操作系統(tǒng)的內(nèi)存訪問差異

JVM和JMM的區(qū)別

說到JMM,我們不得不提到它經(jīng)常被人所搞混淆的另一個(gè)概念JVM,我們用一張表來直觀表現(xiàn)出它們的區(qū)別。

JVM內(nèi)存結(jié)構(gòu)

Java內(nèi)存模型
核心關(guān)注點(diǎn)數(shù)據(jù)存儲(chǔ)的物理/邏輯分區(qū)線程與內(nèi)存的交互規(guī)則
內(nèi)容堆、棧、方法區(qū)等內(nèi)存區(qū)域主內(nèi)存、工作內(nèi)存抽象概念
目的內(nèi)存分配與管理多線程內(nèi)存可見性控制

2.JMM核心概念

主內(nèi)存和工作內(nèi)存

  • 主內(nèi)存:所有線程共享的內(nèi)存區(qū)域,存儲(chǔ)所有實(shí)例字段、靜態(tài)字段和數(shù)組元素

  • 工作內(nèi)存:每個(gè)線程私有的內(nèi)存空間,存儲(chǔ)線程使用變量的副本

當(dāng)某個(gè)線程需要使用到內(nèi)存中的變量時(shí),他會(huì)先從主內(nèi)存中復(fù)制一份該變量的副本到自己的工作內(nèi)存當(dāng)中,使用完后再將該變量寫入主內(nèi)存的共享內(nèi)存中。

內(nèi)存間的交互操作

  • lock/unlock:作用于主內(nèi)存,標(biāo)識(shí)變量為線程獨(dú)占狀態(tài)

  • read/load:從主內(nèi)存讀取變量到工作內(nèi)存

  • use/assign:工作內(nèi)存中使用和賦值操作

  • store/write:將工作內(nèi)存變量寫回主內(nèi)存

內(nèi)存三大特性

原子性

核心概念:原子性指一個(gè)操作或一系列操作要么全部執(zhí)行成功,要么全部不執(zhí)行,不會(huì)出現(xiàn)執(zhí)行到一半的狀態(tài)。

// 原子操作示例
int x = 10;           // 原子的:一次性賦值
boolean flag = true;  // 原子的

// 非原子操作示例
int i = 0;
i++;                  // 非原子的,實(shí)際包含3個(gè)步驟:
                      // 1.讀取i的值到寄存器 
                      // 2.寄存器值加1     
                      // 3.寫回內(nèi)存        

可見性

核心概念:可見性指當(dāng)一個(gè)線程修改了共享變量的值,其他線程能夠立即看到修改后的值。

 private boolean running = true;  // 主內(nèi)存中的變量
    
    public void run() {
        while (running) {  // 工作內(nèi)存中的副本
            // 看不到running被改為false
        }
    }
    
    public void stop() {
        running = false;  // 修改主內(nèi)存,但工作內(nèi)存可能沒更新
    }

有序性

核心概念:有序性指程序執(zhí)行的順序按照代碼的先后順序執(zhí)行。但在多線程或優(yōu)化環(huán)境下,指令可能被重排序。

重排序原因:

  • 編譯器優(yōu)化重排序

  • 處理器指令級(jí)并行重排序

  • 內(nèi)存系統(tǒng)重排序

 private int x = 0;
 private boolean flag = false;
    
    // 線程1執(zhí)行
    public void writer() {
        x = 42;          // 1
        flag = true;     // 2 可能被重排到1之前!
    }
    
    // 線程2執(zhí)行
    public void reader() {
        if (flag) {      // 3
            System.out.println(x);  // 可能輸出0而不是42!
        }
    }

3.Happens-Before規(guī)則

Happens-Before規(guī)則介紹

Happens-Before是JMM的核心概念,它定義了兩個(gè)操作之間的偏序關(guān)系

  • 如果操作A happens-before? 操作B

  • 那么A的所有寫操作對(duì)B的讀操作都是可見

有點(diǎn)難看懂,我們用一個(gè)簡單的例子就能快速理解

// 核心:happens-before ≠ 時(shí)間先后
int x = 0;
int y = 0;

// 時(shí)間上:先執(zhí)行1,后執(zhí)行2
x = 1;      // 1
y = x + 1;  // 2

// 邏輯上:1 happens-before 2
// 所以2一定能看到1寫入的值

A happens-before B 翻譯過來就是:A對(duì)B可見。

六大happens-before規(guī)則

  • 程序次序規(guī)則:線程內(nèi),按照程序代碼順序,前面的操作happens-before后面的操作。
  • 監(jiān)視器鎖規(guī)則:對(duì)一個(gè)鎖的解鎖操作happens-before后續(xù)對(duì)這個(gè)鎖的加鎖操作。
  • volatile變量規(guī)則:對(duì)一個(gè)volatile變量的操作happens-before后續(xù)對(duì)這個(gè)變量的操作。
  • 線程啟動(dòng)規(guī)則:Thread對(duì)象的start()方法調(diào)用happens-before該線程的每一個(gè)動(dòng)作。
  • 線程終止規(guī)則:線程中的所有操作happens-before其他線程檢測(cè)到該線程已經(jīng)終止
  • 傳遞性規(guī)則:如果A happens-before B,且B happens-before C,那么A happens-before C

4.volatile關(guān)鍵字

核心概述:volatile是一個(gè)重要的關(guān)鍵字,用于告知編譯器某個(gè)變量的值可能會(huì)被程序外部的因素意外修改,從而避免編譯器對(duì)該變量進(jìn)行優(yōu)化。它的主要作用是確保每次訪問變量時(shí)都從內(nèi)存中讀取最新的值,而不是使用寄存器中的緩存值。

volatile提供了兩大保證:

  • 可見性:修改立即對(duì)所有線程可見
  • 有序性:禁止指令重排序
 private volatile boolean flag = false;
    private int count = 0;
    
    public void writer() {
        count = 42;        // 普通寫操作
        flag = true;       // volatile寫操作
    }
    
    public void reader() {
        if (flag) {        // volatile讀操作
            // 這里一定能看到count=42
            System.out.println(count);
        }
    }

5.JMM的常見誤區(qū)

volatile無法保證原子性

volatile可以保證可見性和有序性,但和synchronized不一樣,不能保證原子性

// 錯(cuò)誤:以為volatile能保證原子性
volatile int count = 0;
count++;  // 非原子操作

// 正確:使用原子類或同步
AtomicInteger atomicCount = new AtomicInteger(0);
atomicCount.incrementAndGet();

指令重排序的陷阱

// 可能由于重排序?qū)е聠栴}
int a = 0;
boolean flag = false;

// 線程1
a = 1;          // 1
flag = true;    // 2 可能重排到1之前

// 線程2
if (flag) {
    System.out.println(a);  // 可能輸出0
}

此時(shí)我們需對(duì)flag使用volatile關(guān)鍵字修飾即可保證在a賦值后再執(zhí)行flag=true操作。

總結(jié)

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

相關(guān)文章

  • c#和java base64不一致的解決方法

    c#和java base64不一致的解決方法

    最近非常郁悶的處理這個(gè)base64的問題,同樣的一個(gè)圖片文件,在java和c#進(jìn)行base64編碼后結(jié)果不一樣,苦惱了很久,下面這篇文章主要給大家介紹了關(guān)于c#和java base64不一致的解決方法,需要的朋友可以參考下
    2018-11-11
  • 一文帶你弄懂Maven拉包(拉取依賴包)原理

    一文帶你弄懂Maven拉包(拉取依賴包)原理

    業(yè)務(wù)需求開發(fā)的時(shí)候,我們總是會(huì)遇到拉不到依賴包的情況,此時(shí)如果不清楚 Maven 拉取依賴包的原理,那么很可能找不到問題所在,今天小編就帶大家了解下 Maven 拉包的原理,讓你在遇到問題的時(shí)候能快速解決,需要的朋友可以參考下
    2023-07-07
  • Java查看變量的數(shù)據(jù)類型的三種方法

    Java查看變量的數(shù)據(jù)類型的三種方法

    Java是一門強(qiáng)類型的編程語言,它對(duì)變量的數(shù)據(jù)類型有嚴(yán)格的限定,在定義變量時(shí)必須聲明變量的數(shù)據(jù)類型,在為變量賦值時(shí)必須賦予與變量同一種類型的值,否則程序會(huì)報(bào)錯(cuò), 所以本文給大家介紹了Java查看變量的數(shù)據(jù)類型的三種方法,需要的朋友可以參考下
    2024-10-10
  • java 抽象類和接口的區(qū)別詳細(xì)解析

    java 抽象類和接口的區(qū)別詳細(xì)解析

    abstractclass和interface是Java語言中對(duì)于抽象類定義進(jìn)行支持的兩種機(jī)制,正是由于這兩種機(jī)制的存在,才賦予了Java強(qiáng)大的面向?qū)ο竽芰?需要了解的朋友可以參考下
    2012-11-11
  • Java異常處理操作 Throwable、Exception、Error

    Java異常處理操作 Throwable、Exception、Error

    這篇文章主要介紹了Java異常處理操作 Throwable、Exception、Error,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • java實(shí)現(xiàn)文件上傳到服務(wù)器

    java實(shí)現(xiàn)文件上傳到服務(wù)器

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)文件上傳到服務(wù)器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • java監(jiān)聽器實(shí)現(xiàn)在線人數(shù)統(tǒng)計(jì)

    java監(jiān)聽器實(shí)現(xiàn)在線人數(shù)統(tǒng)計(jì)

    這篇文章主要為大家詳細(xì)介紹了java監(jiān)聽器實(shí)現(xiàn)在線人數(shù)統(tǒng)計(jì),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-11-11
  • Java完全二叉樹的創(chuàng)建與四種遍歷方法分析

    Java完全二叉樹的創(chuàng)建與四種遍歷方法分析

    這篇文章主要介紹了Java完全二叉樹的創(chuàng)建與四種遍歷方法,結(jié)合實(shí)例形式分析了完全二叉樹的概念、定義及遍歷操作相關(guān)實(shí)現(xiàn)技巧,并對(duì)比分析了滿二叉樹與完全二叉樹的區(qū)別,需要的朋友可以參考下
    2017-11-11
  • 重新對(duì)Java的類加載器的學(xué)習(xí)方式

    重新對(duì)Java的類加載器的學(xué)習(xí)方式

    這篇文章主要介紹了重新對(duì)Java的類加載器的學(xué)習(xí)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-05-05
  • 徹底解決tomcat中文亂碼問題方案

    徹底解決tomcat中文亂碼問題方案

    這篇文章主要介紹了徹底解決tomcat中文亂碼問題方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11

最新評(píng)論

上林县| 黔南| 马边| 比如县| 依安县| 谷城县| 千阳县| 福泉市| 绥德县| 平陆县| 长乐市| 台安县| 福建省| 抚远县| 宜兴市| 彰化县| 嘉峪关市| 舒兰市| 澎湖县| 呼图壁县| 行唐县| 兴业县| 陆丰市| 南岸区| 澄迈县| 赤壁市| 东安县| 乐安县| 玉龙| 崇仁县| 嘉峪关市| 桐庐县| 井研县| 龙胜| 琼海市| 张家港市| 台山市| 溧阳市| 秭归县| 澜沧| 台安县|