深刻理解java內存模型一

併發編程模型的分類

概要

併發編程中,須要處理兩個問題:java

  1. 線程之間如何通訊
  2. 線程之間如何同步

1.線程通訊:

定義:是指線程之間以何種機制來交換信息。
在命令式編程中,線程通訊機制有兩種:共享內存消息傳遞程序員

共享內存的併發模型裏,線程之間共享程序的公共狀態,線程之間經過寫-讀內存中的公共狀態來隱式的通訊。
消息傳遞的併發模型裏,線程之間沒有公共狀態,線程之間必須經過明確的發送消息來顯示的進行通訊。編程

2.同步:

定義:是指程序用於控制不一樣線程之間操做發生相對順序的機制。
共享內存併發模型裏,同步是顯示進行的。程序必須指定某個方法或某個代碼段須要在線程之間互斥執行。
消息傳遞併發模型裏,因爲消息的發送必須在消息的接收以前,所以同步是隱式進行的。數組

3.java內存模型特性

java採用的是共享內存模型,java線程之間的通訊是隱式進行,整個通訊過程對程序透明。緩存

java內存模型的抽象

在java中,全部實例域,靜態域和數組元素都存儲在堆內存中,堆內存在線程之間共享(共享變量)
局部變量(Local variables),方法定義參數(java語言規範稱之爲formal method parameters)和異常處理器參數(exception handler parameters)不會在線程之間共享,它們不會有內存可見性問題,也不受內存模型的影響。併發

Java線程之間的通訊由Java內存模型(本文簡稱爲JMM)控制,JMM決定一個線程對共享變量的寫入什麼時候對另外一個線程可見。app

從抽象的角度來看,JMM定義了線程和主內存之間的抽象關係:線程之間的共享變量存儲在主內存(main memory)中,每一個線程都有一個私有的本地內存(local memory),本地內存中存儲了該線程以讀/寫共享變量的副本。性能

本地內存是JMM的一個抽象概念,並不真實存在。它涵蓋了緩存,寫緩衝區,寄存器以及其餘的硬件和編譯器優化。優化

重排序

爲了提升性能,編譯器和處理器經常會對指令作重排序。重排序分爲三種類型:線程

  1. 編譯器優化的重排序。
  2. 指令級並行的重排序
  3. 內存系統的重排序。

處理器重排序與內存屏障指令

處理器對內存的讀/寫操做的執行順序,不必定與內存實際發生的讀/寫操做順序一致!

這裏處理器A和處理器B能夠同時把共享變量寫入本身的寫緩衝區(A1,B1),而後從內存中讀取另外一個共享變量(A2,B2),最後才把本身寫緩存區中保存的髒數據刷新到內存中(A3,B3)。當以這種時序執行時,程序就能夠獲得x = y = 0的結果。
從內存操做實際發生的順序來看,直處處理器A執行A3來刷新本身的寫緩存區,寫操做A1纔算真正執行了。雖然處理器A執行內存操做的順序爲:A1->A2,但內存操做實際發生的順序倒是:A2->A1。此時,處理器A的內存操做順序被重排序了。

happens-before

若是一個操做執行的結果須要對另外一個操做可見,那麼這兩個操做之間必需要存在happens-before關係。這裏提到的兩個操做既能夠是在一個線程以內,也能夠是在不一樣線程之間。

與程序員密切相關的happens-before規則以下:

  • 程序順序規則:一個線程中的每一個操做,happens- before 於該線程中的任意後續操做。
  • 監視器鎖規則:對一個監視器鎖的解鎖,happens- before 於隨後對這個監視器鎖的加鎖。
  • volatile變量規則:對一個volatile域的寫,happens- before 於任意後續對這個volatile域的讀。
  • 傳遞性:若是A happens- before B,且B happens- before C,那麼A happens- before C。


相關文章
相關標籤/搜索