Java併發——關於Java內存模型(JMM),你需要知道什麼?

一、JMM採用的什麼內存模型?我們這個內存模型看起來是怎麼樣的?

併發編程中有兩個主要的問題,一個是不同的線程之間怎麼通信;二個是如何保證不同線程之間的同步。如果一個模型能夠解決這兩個問題,那麼就可以用來描述併發編程模型。

在命令式編程中,線程之間通信的方式有兩種,一種是通過共享內存在實現通信,稱爲共享式的併發模型;另一種是顯式的發送消息來實現通信,稱爲消息傳遞式的併發模型

在內存共享式的併發模型中,線程之間存在公共變量,通過公共變量的“寫-讀”操作進行隱式的通信;消息傳遞式的併發模型中,線程之間沒有公共的變量,因此需要顯式的發送消息來進行通信。

同步是指“程序中不同線程之間的操作發生相對順序的機制”。在共享式併發模型中,必須要顯式的制定哪些方法、代碼塊需要互斥執行;在消息傳遞式的併發模型中,因爲消息的發送必須在接收之前,因此實現了隱式的同步。

JMM採用的就是共享式的併發模型。

那麼JMM看起來是怎麼樣的呢?接下來我們看一看抽象的JMM模型

在Java中,實例變量、靜態域和數組元素都存儲在堆內存中,堆內存在線程之間共享;局部變量、方法定義參數和異常處理線程參數不會在線程之間共享,因此也不會有內存可見性問題。

Java線程間的通信由JMM控制,它決定了一個線程對共享變量的寫入何時對其它的線程可見,抽象的來看,JMM定義了線程和主內存之間的抽象關係:線程之間的共享變量存儲在主內存中,每個線程都有一個私有的本地內存,這個本地內存用來存儲共享變量的副本線程一般對本地存儲的共享變量進行操作,要必要的時候把本地存儲的變量刷新到主內存中,或者從主內存中下載最新的共享變量值,這個時候,不同的線程之間就實現了通信。

*注意:JMM是一個抽象的概念,並不是真實存在的,本地存儲也不是真實存在的一個內存區域,他涵蓋了緩存,寫緩衝區,寄存器等。


二、關於重排序

在執行程序時,爲了提高性能,編譯器和處理器會對指令進行重排序。有以下3種重排序:編譯器重排序、指令集並行的重排序、內存系統的重排序,實際的指令執行的順序都是源代碼經過這3中重排序後的順序,其中第一個屬於編譯器重排序,後兩者屬於處理器重排序。

對於編譯器重排序,Java編譯器會禁止特定類型的重排序;

對於指令集重排序,JMM重排序規則在生成字節碼的時候,爲保證內存可見性,會插入特定類型的內存屏障阻止處理器重排序。

JMM把內存屏障分爲4類:


編譯器和處理器在重排時會遵守“數據依賴性”,不會改變存在數據依賴的操作的執行順序,這裏的數據依賴性指在單個處理器中執行時的數據依賴性,對在多個處理器中執行的有數據依賴的操作不予考慮。


三、happenbefore規則

JMM使用happen-before概念來闡述操作之間的內存可見性,在JMM中,如果要一個操作對另一個操作可見,就必須要讓這兩個操作之間有happen-before關係。happen-before的規則如下:

1、程序順序規則:在同一個線程中,線程中的每個操作happen-before於其後的每個操作;

2、監視器規則:對於一個監視器,鎖的釋放happen-before於該鎖的下一次獲取;

3、volatile變量規則:對於volatile變量,寫操作happen-before於對這個變量的隨後的讀;

4、傳遞性規則:如果A happen-before B,B happen-before C, 那麼A happen-before C;

*注意:A happen-before B不是說A必須要在B前面執行,只是A的操作對B可見即可,也就是說A、B操作重排序後結果不發生改變即可。


四、什麼是順序一致性?

順序一致性模型是一個理論上的模型,在設計的時候,處理器和編譯器的內存模型都會參考這個模型。

在發生數據競爭時,比如一個線程要對共享變量進行寫操作,另一個線程要對該變量進行讀操作,那麼如果程序正確同步了,就會保證程序的執行具有“順序一致性”,否則不具有。

順序一致性模型可以理解爲把並行的操作串行化,任意一個時刻只能有一個線程鏈接到主內存,並對主內存中的共享變量進行操作。

具有順序一致性的模型看起來基礎油一下特點:

雖然經過重排序以後整體上的操作看似無序,但是對於所有線程來說,看到的操作執行順序一定是一致的。而JMM中本身是不具有順序一致性的,也就是說,在未同步的JMM中,整體順序看起來是無序的,每個線程看到的順序號可能是不一樣的,這樣每次執行的結果都可能不一樣,常常超出預期。


五、同步原語(Synchronized、volatile、final)的同步語義

volatile語義解析:

Synchronized語義解析:

final語義解析:

(未完待續。。。)

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