併發程式設計---JMM模型

攀爬的阿杜發表於2020-09-29

引言

在瞭解本文之前,我們知道所謂的併發程式設計就是平日中接觸的多執行緒程式設計,既然扯到了多執行緒,那一定繞不開多執行緒的一些特性以及每個執行緒的結構或者說是執行緒的記憶體模型。接下來,我們從JMM(Java執行緒記憶體模型)來進行一些原理上的剖析。

多執行緒的關係分為三種:

1.同步:執行緒之間的協作
2.互斥:常見的互斥鎖
3.分工:大任務的拆解

多執行緒經常遇到的問題:

1.死鎖
2.資源共享問題
3.CPU排程問題(執行緒是由CPU來排程,JVM是沒有許可權的)
4.髒讀
5.原子性問題

併發的特性是什麼?本質又是解決什麼問題呢?

其實答案可以歸為一種,即是特性又是其解決的問題點,可分為下面三種:
1.原子性
2.可見性
3.有序性

JMM模型

JMM(Java Memory Model),即Java執行緒記憶體模型,它是一個抽象的概念。為何說是一個抽象的概念,因為JSR133定義的規範,並不是實際存在,它遮蔽了一些作業系統的差異,對其在任何OS上的執行概念做了一個通用的描述。

模型的作用

它定義了一組規則,通過這組規則控制各個變數在共享資料區域和私有資料區域的訪問方式,JMM則是圍繞原子性、有序性、可見性來展開的。

簡單的JMM模型圖
在這裡插入圖片描述

由此我們可以看到,每個執行緒都有各自的工作記憶體,也會與其他執行緒共享一個主記憶體,至於圖中標註的共享標量副本,可以先看下主記憶體中的共享變數,思考一下它們之間的關係。

對於多個執行緒用到的共享變數,每個執行緒是將使用的共享變數拷貝副本到私有工作記憶體中來進行操作,操作完成會將新值回寫到主記憶體中,我們可以再來細緻的分析一下工作記憶體的結構,如圖下所示

在這裡插入圖片描述

看到這幅圖,如果對JVM有所瞭解的話,理解起來並不困難。因為JVM中五大區域,其中虛擬機器棧是屬於執行緒私有的,而裡面每個執行方法或都是一個棧幀,裡面方法內一些變數也都存在棧上

JMM與硬體記憶體架構的關係

為什麼又要扯到硬體記憶體架構上呢?大家不妨來思考一下,JVM沒有許可權進行執行緒排程,那麼是誰來控制著執行緒的上下文切換和執行順序呢?

Java執行緒是核心級執行緒,其所有的排程都是CPU來控制的,當一個java執行緒啟動,其實是對映到OS系統執行緒,再來呼叫核心執行緒來實現。這就是大家口中常說的:執行緒從使用者態轉為核心態
Java Thread >> OS Thread >> pthread_create

我們可以來初步的瞭解一下CPU的快取架構,如下圖:
在這裡插入圖片描述

從圖上我們可以看出,我們的所有的操作都是要通過IO匯流排來向記憶體中寫資料,然後再由CPU來進行讀寫,那麼到底是CPU內部又是如何做到的一系列操作,這時我們就需要提到CPU暫存器與快取記憶體

CPU暫存器與快取記憶體

CPU快取即高速緩衝儲存器,是位於CPU與主記憶體間的一種容量較小但速度很高的儲存器。由於CPU的速度遠高於主記憶體,CPU直接從記憶體中存取資料要等待一定時間週期,Cache中儲存著CPU剛用過或迴圈使用的一部分資料,當CPU再次使用該部分資料時可從Cache中直接呼叫,減少CPU的等待時間,提高了系統的效率。

在這裡插入圖片描述
圖上所示為目前流程的多核CPU架構,可以看到每個CPU核裡面都有獨自的暫存器與L1、L2級別快取記憶體,L3級也為三級快取屬於共享的。

暫存器相當於我們的棧幀來進行指令的執行,它在與主存還有一道中間過程,就是L1、L2、L3級快取記憶體,可以看出
1.等級劃分 L1 > L2 > L3
2.快取速度 L1 > L2 > L3
3.緩衝區大小 L1 < L2 < L3

其實上面這三種關係我們可以從一個角度上來開始分析,就是緩衝區大小,如下圖所示:

在這裡插入圖片描述
緩衝區越大,儲存的變數就越多,對應的搜尋範圍越大,導致搜尋時間就越長,最終導致其速度最慢,在上述描述中我們提到了一個名詞“時鐘週期”,指的就是不同級別的快取對應查詢的一個時間週期

在這裡插入圖片描述
當暫存器需要資料的時候如果從主存中獲取,大概需要等待167個時鐘週期,而從L1快取中獲取僅僅需要4個時鐘週期,這其中提升的效率是非常明顯的,所以

相關文章