Java內存模型(JMM)

Java內存模型(JMM)

1. 計算機內存系統

計算機在執行程序時,每條指令都是在CPU中執行的,而執行指令過程當中,勢必會涉及到數據的讀取和寫入。java

因爲在程序運行過程當中,臨時數據是存放在主存(物理內存)中的,這時就存在一個問題,因爲CPU執行指令的速度很快,而從內存讀取和寫入數據的過程與其相比速度要慢得多,所以若是任什麼時候候對數據的操做都要經過和內存的交互來進行,會大大下降指令執行的速度。緩存

所以CPU中就有了高速緩存。當程序在運行過程當中,會將運算須要的數據從主存複製一份到CPU的高速緩存中,當CPU進行計算時就能夠直接從它的高速緩存中讀取和寫入數據,運算結束以後,再將高速緩存中的數據刷新到主存當中去。多線程

2. JMM內存模型

在Java虛擬機規範中試圖定義一種Java內存模型(Java Memory Model,JMM)來屏蔽各個硬件平臺和操做系統的內存訪問差別,以實現讓Java程序在各類平臺下都能達到一致的內存訪問效果。併發

JMM定義了線程和主內存之間的抽象關係:線程之間的共享變量存儲在主內存(Main Memory)中,每一個線程都有一個私有的本地內存(Local Memory),本地內存中存儲了該線程讀/寫共享變量的副本。app

image-20200812233547123

若是線程A與線程B之間要通訊的話,必需要經歷下面2個步驟。優化

  • 線程A把本地內存A中更新過的共享變量刷新到主內存中去。
  • 線程B到主內存中去讀取線程A以前已更新過的共享變量。

3. JMM內存模型三大特性

原子性:一個操做或多個操做,要麼所有執行而且執行過程當中不會被任何因素打斷,要麼就不執行。this

  • 對於基本數據類型變量的原子性操做由JUC包原子類中的AtomicInteger等來實現;
  • 對於更大範圍操做的原子性,使用 synchronizedLock 來實現。

可見性:指當多個線程訪問同一個變量時,一個線程修改了這個變量的值,其餘線程可以當即看獲得修改的值操作系統

  • volatile:當一個共享變量被volatile修飾時,它會保證修改的值會當即被更新到主存,當有其餘線程須要讀取時,它會去內存中讀取新值。
  • synchronizedLock:保證同一時刻只有一個線程獲取鎖而後執行同步代碼,而且在釋放鎖以前會將對變量的修改刷新到主存當中,所以能夠保證可見性。
  • final:被 final 關鍵字修飾的字段一旦初始化完成,而且沒有發生 this 逃逸(其它線程經過 this 引用訪問到初始化了一半的對象),也能保證對其餘線程的可見性。

有序性:程序執行的順序按照代碼的前後順序執行。線程

  • 指令重排序:通常來講,處理器爲了提升程序運行效率,可能會對輸入代碼進行優化,它不保證程序中各個語句的執行前後順序同代碼中的順序一致,可是它會保證程序最終執行結果和代碼順序執行的結果是一致的(順序不一致,但結果一致)。重排序過程不會影響到單線程程序的執行,卻會影響到多線程併發執行的正確性。對象

    源代碼 -> 編譯器優化的重排 -> 指令並行的重排 -> 內存系統的重排 ->最終執行的指令

  • 保證有序性的方法

    • volatile關鍵字
    • 經過synchronized和Lock來保證有序性,其能夠保證每一個時刻是有一個線程執行同步代碼,至關因而讓線程順序執行同步代碼,天然也就保證了有序性;
    • Java內存模型具有一些先天的「有序性」,即不須要經過任何手段就可以獲得保證的有序性,一般稱爲happens-before原則。在JMM中,若是一個操做執行的結果須要對另外一個操做可見,那麼這兩個操做之間必需要存在happens-before關係。這兩個操做既能夠在一個線程以內,也能夠在不一樣線程之間。happens-before的一些重要規則:
      • 程序順序規則:一個線程內,按照代碼順序,書寫在前的操做線性發生於先行在後的操做;
      • 監視器鎖規則:一個unlock操做先行發生於後面對同一個鎖的lock操做;
      • volatile變量規則:對一個變量的寫操做先行發生於後面對這個變量的讀操做;
      • 傳遞性:若操做A先行發生於B,而操做B又先行發生於C,則能夠得出操做A先行發生於C。
相關文章
相關標籤/搜索