JAVA面試我說不清楚-Java內存模型?

你好我是辰兮,很高興與你分享近期學習總結,上一篇整理完Java虛擬機內存結構,爲了對比學習,本篇是對Java內存模型的介紹,整理完收穫頗多,分享出來,希望對你們理解學習有幫助。



一、簡述Java內存模型

Java內存模型(Java Memory Model,JMM)是java虛擬機規範定義的,用來屏蔽掉java程序在各種不同的硬件和操作系統對內存的訪問的差異,這樣就可以實現java程序在各種不同的平臺上都能達到內存訪問的一致性。在這裏插入圖片描述
可以避免像c++等直接使用物理硬件和操作系統的內存模型在不同操作系統和硬件平臺下表現不同,比如有些c/c++程序可能在windows平臺運行正常,而在linux平臺卻運行有問題。

ps:JVM中的堆啊、棧啊、方法區什麼的,是Java虛擬機的內存結構。內存模型概念如上,千千萬萬不要再搞混淆了。


二、CPU和緩存一致性

計算機在執行程序的時候,每條指令都是在CPU中執行的,而執行的時候,又免不了要和數據打交道。而計算機上面的數據,是存放在主存當中的,也就是計算機的物理內存。

隨着CPU技術的發展,CPU的執行速度越來越快。而由於內存的技術並沒有太大的變化,所以從內存中讀取和寫入數據的過程和CPU的執行速度比起來差距就會越來越大,這就導致CPU每次操作內存都要耗費很多等待時間。

不能因爲內存的讀寫速度慢,就不發展CPU(中央處理器)技術了吧。

人們想到了用緩存來解決這個問題,就是在CPU和內存之間增加高速緩存。緩存的概念大家都知道,就是保存一份數據拷貝。他的特點是速度快,內存小,並且昂貴。

在這裏插入圖片描述

當程序在運行過程中,會將運算需要的數據從主存複製一份到CPU的高速緩存當中,那麼CPU進行計算時就可以直接從它的高速緩存讀取數據和向其中寫入數據,當運算結束之後,再將高速緩存中的數據刷新到主存當中。


Java內存模型的引入

Java內存模型規定了①所有的變量都存儲在主內存中②每條線程還有自己的工作內存,③線程的工作內存中保存了該線程中是用到的變量的主內存副本拷貝,線程對變量的所有操作都必須在工作內存中進行,而不能直接讀寫主內存。

不同的線程之間也無法直接訪問對方工作內存中的變量,線程間變量的傳遞均需要自己的工作內存和主存之間進行數據同步進行。
在這裏插入圖片描述

JMM就作用於工作內存和主存之間數據同步過程。

他規定了如何做數據同步以及什麼時候做數據同步。


注意主內存和工作內存與JVM內存結構中的Java堆、棧、方法區等並不是同一個層次的內存劃分,無法直接類比。

小結JMM是一種規範,目的是解決由於多線程通過共享內存進行通信時,存在的本地內存數據不一致、編譯器會對代碼指令重排序、處理器會對代碼亂序執行等帶來的問題。目的是保證併發編程場景中的原子性、可見性和有序性。


三、Java內存模型的實現

瞭解Java多線程的朋友都知道,在Java中提供了一系列和併發處理相關的關鍵字,比如volatile、synchronized、final、concurren包等。其實這些就是Java內存模型封裝了底層的實現後提供給程序員使用的一些關鍵字。

在開發多線程的代碼的時候,我們可以直接使用synchronized等關鍵字來控制併發,從來就不需要關心底層的編譯器優化、緩存一致性等問題。所以,Java內存模型,除了定義了一套規範,還提供了一系列原語,封裝了底層實現後,供開發者直接使用。

重點要介紹的就是,我們前面提到,併發編程要解決原子性、有序性和一致性的問題,我們就再來看下,在Java中,分別使用什麼方式來保證。


1、原子性

  • 在Java中,爲了保證原子性,提供了兩個高級的字節碼指令monitorenter和monitorexit。在synchronized的實現原理文章中,介紹過,這兩個字節碼,在Java中對應的關鍵字就是synchronized。
  • 因此,在Java中可以使用synchronized來保證方法和代碼塊內的操作是原子性的。

2、可見性

  • Java內存模型是通過在變量修改後將新值同步回主內存,在變量讀取前從主內存刷新變量值的這種依賴主內存作爲傳遞媒介的方式來實現的。
  • Java中的volatile關鍵字提供了一個功能,那就是被其修飾的變量在被修改後可以立即同步到主內存,被其修飾的變量在每次是用之前都從主內存刷新。因此,可以使用volatile來保證多線程操作時變量的可見性。
  • 除了volatile,Java中的synchronized和final兩個關鍵字也可以實現可見性。只不過實現方式不同,這裏不再展開了。

3、有序性

  • 在Java中,可以使用synchronized和volatile來保證多線程之間操作的有序性。
  • 實現方式有所區別:volatile關鍵字會禁止指令重排synchronized關鍵字保證同一時刻只允許一條線程操作

簡單的介紹完了Java併發編程中解決原子性、可見性以及有序性可以使用的關鍵字。大家發現好像synchronized關鍵字是萬能的,他可以同時滿足以上三種特性,這其實也是很多人濫用synchronized的原因。

但是synchronized是比較影響性能的,雖然編譯器提供了很多鎖優化技術,但是也不建議過度使用。


大家可以參考《深入理解Java虛擬機》

The best investment is to invest in yourself

在這裏插入圖片描述

2020.05.21 記錄辰兮的第68篇博客

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章