Java 線程內存模型
1. 前言
本節內容是從操作系統的層面談并發,本節課程我們需要掌握如下內容:
- 了解 Java 的內存模型定義,是 Java 并發編程基本原理的基礎知識;
- 從概念上了解線程的私有內存空間和主內存,能夠從全局上了解線程是如何進行內存數據的存取操作的;
- 了解線程擁有私有空間的意義,私有空間能夠為線程提供獨有的數據,其他線程不可干擾;
- 在多線程環境下,主內存操作共享變量需要注意的事項需謹記,數據安全問題很重要;
- Java 線程也是擁有生命周期的,了解它的生命周期,從宏觀上了解線程。
2. 什么是 Java 的內存模型
定義: Java 內存模型(即 Java Memory Model,簡稱 JMM)本身是一種抽象的概念,并不真實存在,它描述的是一組規則或規范,通過這組規范定義了程序中各個變量(包括實例字段,靜態字段和構成數組對象的元素)的訪問方式。
3. Java 線程的私有內存和主內存
首先看下圖,圖中展示了Java 的內存模型。
工作內存(私有):由于JVM 運行程序的實體是線程,而每個線程創建時 JVM 都會為其創建一個工作內存(??臻g),用于存儲線程私有的數據。線程私有的數據只能供自己使用,其他線程不能夠訪問到當前線程私有的內存空間,保證了不同的線程在處理自己的數據時,不受其他線程的影響。
主內存(共享):Java 內存模型中規定所有變量都存儲在主內存,主內存是共享內存區域,所有線程都可以訪問。從上圖中可以看到,Java 的并發內存模型與操作系統的 CPU 運行方式極其相似,這就是 Java 的并發編程模型。通過創建多條線程,并發的進行操作,充分利用系統資源,達到高效的并發運算。
4. 線程擁有私有空間的意義
我們知道,線程的私有空間中存儲的數據,僅供當前線程自己使用,其他線程不能夠對數據進行訪問。線程的私有空間會存放很多程序運行時所必須的數據,如:
程序計數器:記錄當前方法執行到了哪里,以便 CPU 切換回來之后能夠繼續執行上次執行到的位置,而不會進行重復執行或者遺漏。
局部變量:局部變量是方法中的變量,只供當前方法使用。
方法參數:Java 方法會定義自己的入參,入參的真實值也會記錄到內存空間供當前線程使用。
由于線程的內存空間會存放很多數據,這里只提以上三中數據以供同學理解線程私有空間的意義。
為了加深理解,我們一起看一個簡單的代碼示例并進行分析:
public class DemoTest{
public static void main(String[] args) {
sum(10); // 解析點 3
}
public static void sum(int num) {
int i = 5; // 解析點 1
set(); //解析點 2
System.out.println("num+i = "+ (num + i));
}
public static void set() {
int i = 100;
}
}
在給出結果之前,我們來分析下:
解析點 1 :設置 i 的值為 5;
解析點 2: 調用 set() 方法,邏輯如下。
public static void set() {
int i = 100;
}
那最終的結果是多少呢?
解析點 3:我們傳入的 sum 的參數值是 10,如果想確定結果,只要確定另外一個加數 i 的值就行了。我們通過分析,在方法 sum(int num) 中的 int i = 5 與方法 set() 中的 int i = 100 是兩個不同的方法的局部變量,屬于線程私有的?;ハ嗖粫绊?,所以set() 方法中的 int i = 100 不會影響最終的結果:
num+i = 15
5. 主內存操作共享變量需要注意的事項
- 確定是否是多線程環境:多線程環境下操作共享變量需要考慮線程的安全性;
- 確定是否有增刪改操作:多線程環境下,如果對共享數據有增加,刪除或者修改的操作,需要謹慎。為了保證線程的同步性,必須對該共享數據進行加鎖操作,保證多線程環境下,所有的線程能夠獲取到正確的數據。如生產者與消費者模型,售票模型。這些會在后續章節進行代碼實戰演練;
- 多線程下的讀操作:如果是只讀操作,對共享數據不需要進行鎖操作,因為數據本身未發生增刪改操作,不會影響獲取數據的準確性。
6. Java 線程的生命周期
每個事物都有其生命周期,也就是事物從出生開始到最終消亡這中間的整個過程。在其整個生命周期的歷程中,會有不同階段,每個階段對應著一種狀態,比如:人的一生會經歷從嬰幼兒、青少年、青壯年、中老年到最終死亡,離開這人世間,這是人一生的狀態。
同樣的,線程作為一種事物,也有生命周期,在其生命周期中也存在著不同的狀態,不同的狀態之間還會有互相轉換。
Java 線程的聲明周期會經歷 6 中不同的狀態變化,后續章節會有詳細描述。從線程的創建到線程執行任務的完成,即 Java 線程的生命周期。
7. 小結
Java 并發理論基礎是基于Java 的內存模型的,了解 Java 內存模型,能夠更有助于后續對并發知識的理解和運用了。Java 的內存模型是并發原理的基礎,在了解內存模型的基礎上去理解共享內存和私有內存,了解不同內存狀態以及 Java 線程的生命周期至關重要。