成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

簡(jiǎn)述Java內(nèi)存模型

ACb0y / 3255人閱讀

摘要:內(nèi)存模型即,簡(jiǎn)稱,其規(guī)范了虛擬機(jī)與計(jì)算機(jī)內(nèi)存時(shí)如何協(xié)同工作的,規(guī)定了一個(gè)線程如何和何時(shí)看到其他線程修改過(guò)的值,以及在必須時(shí),如何同步訪問(wèn)共享變量。內(nèi)存模型要求調(diào)用棧和本地變量存放在線程棧上,對(duì)象存放在堆上。

Java內(nèi)存模型即Java Memory Model,簡(jiǎn)稱JMM,其規(guī)范了Java虛擬機(jī)與計(jì)算機(jī)內(nèi)存時(shí)如何協(xié)同工作的,規(guī)定了一個(gè)線程如何和何時(shí)看到其他線程修改過(guò)的值,以及在必須時(shí),如何同步訪問(wèn)共享變量。

JVM的內(nèi)存分配

在解釋Java內(nèi)存模型之前,我們先了解下JVM的內(nèi)存分配的幾個(gè)概念,如下圖所示,Java內(nèi)存模型把內(nèi)存分為兩大塊,一個(gè)是堆一個(gè)是棧。

堆heap:運(yùn)行時(shí)的數(shù)據(jù)區(qū),由垃圾回收負(fù)責(zé),動(dòng)態(tài)分配大小。存取速度較慢;

棧stack:存取速度比堆快,僅次于寄存器,數(shù)據(jù)可以共享,大小和生存期等是固定的。

Java內(nèi)存模型要求調(diào)用棧和本地變量存放在線程棧上,對(duì)象存放在堆上。
一個(gè)變量也可能是指向一個(gè)對(duì)象的引用,引用這個(gè)變量是放在線程棧上,但對(duì)象本身是放在堆上的。
一個(gè)對(duì)象它可能包含方法(methodOne..),方法包含本地變量(Local variable1..),這些本地變量都仍然是放在線程棧上的,即使這些方法所屬的對(duì)象存放在堆上,一個(gè)對(duì)象的成員變量可能會(huì)隨著對(duì)象自身存放在堆上,不管這個(gè)對(duì)象是原始類型還是引用類型。
靜態(tài)成員變量跟隨著類的定義存放在堆上,存放在堆上的對(duì)象可以被所持有對(duì)這個(gè)對(duì)象引用的線程訪問(wèn)。
當(dāng)一個(gè)線程可以訪問(wèn)一個(gè)對(duì)象時(shí),它也可以訪問(wèn)這個(gè)對(duì)象的成員變量,如果兩個(gè)線程同時(shí)調(diào)用同一個(gè)對(duì)象上的同一個(gè)方法,他們都會(huì)訪問(wèn)這個(gè)對(duì)象的成員變量,但是每一個(gè)線程都擁有了成員變量的私有拷貝。

計(jì)算機(jī)硬件架構(gòu)

接下來(lái)我們?cè)賮?lái)看看計(jì)算機(jī)硬件架構(gòu)的圖示:

這里是個(gè)多CPU的結(jié)構(gòu),一個(gè)cpu中可能還包含多核。因此我們可以看出,在有兩個(gè)或者多個(gè)cpu的現(xiàn)代計(jì)算機(jī)上,同時(shí)運(yùn)行多個(gè)線程是有可能的,而且每個(gè)cpu在某個(gè)時(shí)刻運(yùn)行一個(gè)線程是沒(méi)問(wèn)題的。若Java程序是多線程的,在Java程序中,每個(gè)cpu上一個(gè)線程是可能同時(shí)并發(fā)執(zhí)行的。

在CPU內(nèi)部有一組CPU寄存器,也就是CPU的儲(chǔ)存器。

CPU操作寄存器的速度要比操作計(jì)算機(jī)主存快的多,在主存和CPU寄存器之間還存在一個(gè)CPU緩存,CPU操作CPU緩存的速度快于主存但慢于CPU寄存器。即CPU操作的速度上主存 < 緩存 < 寄存器。某些CPU可能有多個(gè)緩存層(一級(jí)緩存和二級(jí)緩存)。計(jì)算機(jī)的主存也稱作RAM,所有的CPU都能夠訪問(wèn)主存,而且主存比上面提到的緩存和寄存器大很多。

當(dāng)一個(gè)CPU需要訪問(wèn)主存時(shí),會(huì)先讀取一部分主存數(shù)據(jù)到CPU緩存,進(jìn)而在讀取CPU緩存到寄存器。當(dāng)CPU需要寫數(shù)據(jù)到主存時(shí),同樣會(huì)先將寄存器的數(shù)據(jù)刷新到CPU緩存,然后再在某些節(jié)點(diǎn)把緩存數(shù)據(jù)刷新到主存。

Java內(nèi)存模型和硬件內(nèi)存架構(gòu)并不一致。硬件內(nèi)存架構(gòu)中并沒(méi)有區(qū)分棧和堆,從硬件上看,所有的線程棧和堆都分布在主主存中,當(dāng)然一部分棧和堆的數(shù)據(jù)也有可能會(huì)存到CPU緩存和寄存器中,如下圖所示,Java內(nèi)存模型和計(jì)算機(jī)硬件內(nèi)存架構(gòu)是一個(gè)交叉關(guān)系:

并發(fā)編程模型的兩個(gè)關(guān)鍵問(wèn)題

在并發(fā)編程中,需要處理兩個(gè)關(guān)鍵問(wèn)題:線程之間如何通信及線程之間如何同步(這里的線程是指并發(fā)執(zhí)行的活動(dòng)實(shí)體)。通信是指線程之間以何種機(jī)制來(lái)交換信息。在命令式編程中,線程之間的通信機(jī)制有兩種:共享內(nèi)存和消息傳遞。

在共享內(nèi)存的并發(fā)模型里,線程之間共享程序的公共狀態(tài),通過(guò)寫-讀內(nèi)存中的公共狀態(tài)進(jìn)行隱式通信。在消息傳遞的并發(fā)模型里,線程之間沒(méi)有公共狀態(tài),線程之間必須通過(guò)發(fā)送消息來(lái)顯式進(jìn)行通信。
同步是指程序中用于控制不同線程間操作發(fā)生相對(duì)順序的機(jī)制。在共享內(nèi)存并發(fā)模型里,同步是顯式進(jìn)行的。程序員必須顯式指定某個(gè)方法或某段代碼需要在線程之間互斥執(zhí)行。
在消息傳遞的并發(fā)模型里,由于消息的發(fā)送必須在消息的接收之前,因此同步是隱式進(jìn)行的。
Java的并發(fā)采用的是共享內(nèi)存模型,Java線程之間的通信總是隱式進(jìn)行,整個(gè)通信過(guò)程對(duì)程序員完全透明。

Java內(nèi)存模型的抽象結(jié)構(gòu)

接下來(lái)我們從抽象角度看看線程和主存之間的抽象關(guān)系:

線程之間的共享變量存儲(chǔ)在主內(nèi)存里,每個(gè)線程都有個(gè)私有的本地內(nèi)存,存儲(chǔ)了該線程以讀/寫共享變量的副本。它涵蓋了緩存、寫緩沖區(qū)、寄存器以及其他的硬件和編譯器優(yōu)化。本地內(nèi)存是JMM的一個(gè)抽象概念,并不真實(shí)存在。

從上圖來(lái)看,如果線程A與線程B之間要通信的話,必須要經(jīng)歷下面2個(gè)步驟。
1)線程A把本地內(nèi)存A中更新過(guò)的共享變量刷新到主內(nèi)存中去。
2)線程B到主內(nèi)存中去讀取線程A之前已更新過(guò)的共享變量。

本地內(nèi)存A和本地內(nèi)存B由主內(nèi)存中共享變量x的副本。假設(shè)初始時(shí),這3個(gè)內(nèi)存中的x值都為0。線程A在執(zhí)行時(shí),把更新后的x值(假設(shè)值為1)臨時(shí)存放在自己的本地內(nèi)存A中。當(dāng)線程A和線程B需要通信時(shí),線程A首先會(huì)把自己本地內(nèi)存中修改后的x值刷新到主內(nèi)
存中,此時(shí)主內(nèi)存中的x值變?yōu)榱?。隨后,線程B到主內(nèi)存中去讀取線程A更新后的x值,此時(shí)線程B的本地內(nèi)存的x值也變?yōu)榱?。
從整體來(lái)看,這兩個(gè)步驟實(shí)質(zhì)上是線程A在向線程B發(fā)送消息,而且這個(gè)通信過(guò)程必須要經(jīng)過(guò)主內(nèi)存。JMM通過(guò)控制主內(nèi)存與每個(gè)線程的本地內(nèi)存之間的交互,來(lái)為Java程序員提供內(nèi)存可見(jiàn)性保證。

Java內(nèi)存模型的同步操作和規(guī)則

為了保證并發(fā)時(shí)程序處理的準(zhǔn)確性,這里就需要一些同步的手段,這里我們介紹一下Java內(nèi)存模型定義的同步的八種操作和一些規(guī)則。

八種操作

lock(鎖定):作用于主內(nèi)存的變量,把一個(gè)變量標(biāo)識(shí)為一條線程獨(dú)占狀態(tài);

unlock(解鎖):作用于主內(nèi)存的變量,把一個(gè)處于鎖定狀態(tài)的變量釋放出來(lái),釋放后的變量才可以被其他線程鎖定;

read(讀取):作用于主內(nèi)存的變量,把一個(gè)變量值從主內(nèi)存?zhèn)鬏數(shù)骄€程的工作內(nèi)存中,以便隨后的load動(dòng)作使用;

load(載入):作用于工作內(nèi)存的變量,它把read操作從主內(nèi)存中得到的變量值放入工作內(nèi)存的變量副本中;

use(使用):作用于工作內(nèi)存的變量,把工作內(nèi)存中的一個(gè)變量值傳遞給執(zhí)行引擎;

assign(賦值): 作用于工作內(nèi)存的變量,它把一個(gè)執(zhí)行引擎接受到的值賦值給工作內(nèi)存的變量;

store(存儲(chǔ)):作用于工作內(nèi)存的變量,把工作內(nèi)存中的一個(gè)變量的值傳送到主內(nèi)存中,以便隨后的write操作;

write(寫入): 作用于主內(nèi)存的變量,他把store操作從工作內(nèi)存中一個(gè)變量的值傳送到主內(nèi)存的變量中。

規(guī)則

不允許read/load,store/write單一出現(xiàn),且必須按順序執(zhí)行,但中間可以插入其他指令;

不允許一個(gè)線程丟棄離他最近的assign操作

不允許一個(gè)線程未發(fā)生assign操作就將數(shù)據(jù)同步至主線程;

一個(gè)新的變量,只能從主內(nèi)存中誕生,不允許在工作內(nèi)存中生成一個(gè)未被初始化的變量。

一個(gè)變量在同一時(shí)刻只允許一個(gè)線程執(zhí)行l(wèi)ock操作,lock可以被同一個(gè)線程執(zhí)行多次,需要相同次數(shù)的unlock操作才能解鎖;

如果一個(gè)變量執(zhí)行了lock操作,則會(huì)清空工作內(nèi)存中的值,執(zhí)行引擎使用這個(gè)變量前需要重新執(zhí)行l(wèi)oad或者assign操作來(lái)拿到初始化變量的值;

如果一個(gè)變量沒(méi)有被lock操作執(zhí)行,則不允許對(duì)其進(jìn)行unlock操作,也不允許unlock一個(gè)被其他線程lock的變量,unlock操作執(zhí)行之前,必須將此變量同步回主內(nèi)存。

參考文檔:

《Java并發(fā)編程的藝術(shù)》

https://blog.csdn.net/suifeng...

https://coding.imooc.com/lear...

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/69274.html

相關(guān)文章

  • JAVA9-12新特性簡(jiǎn)述

    摘要:本文是個(gè)人在企業(yè)內(nèi)部分享使用的簡(jiǎn)要大綱,列舉了的重要更新,文章的結(jié)構(gòu)較簡(jiǎn)單,也不規(guī)范,鑒于近期寫若干文章時(shí)總會(huì)忘記一些新特性所處的版本,特將此大綱流留用。 本文是個(gè)人在企業(yè)內(nèi)部分享使用的簡(jiǎn)要大綱,列舉了JAVA9-12的重要更新,文章的結(jié)構(gòu)較簡(jiǎn)單,也不規(guī)范,鑒于近期寫若干文章時(shí)總會(huì)忘記一些新特性所處的版本,特將此大綱流copy留用。 一 JAVA9 新特性 1.Java Platfo...

    TigerChain 評(píng)論0 收藏0
  • 史上最全阿里 Java 面試題總結(jié)

    摘要:以下為大家整理了阿里巴巴史上最全的面試題,涉及大量面試知識(shí)點(diǎn)和相關(guān)試題。的內(nèi)存結(jié)構(gòu),和比例。多線程多線程的幾種實(shí)現(xiàn)方式,什么是線程安全。點(diǎn)擊這里有一套答案版的多線程試題。線上系統(tǒng)突然變得異常緩慢,你如何查找問(wèn)題。 以下為大家整理了阿里巴巴史上最全的 Java 面試題,涉及大量 Java 面試知識(shí)點(diǎn)和相關(guān)試題。 JAVA基礎(chǔ) JAVA中的幾種基本數(shù)據(jù)類型是什么,各自占用多少字節(jié)。 S...

    winterdawn 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<