java 內存模型

  1.內存模型java

  java中,全部實例域、靜態域和數組元素存儲在堆內存中,堆內存在線程之間共享。局部變量,方法參數和異常參數不會在線程之間共享,它們不會有內存可見性問題,也不受內存模型的影響。數組

  Java線程之間的通訊由Java內存模型控制,內存模型決定一個線程對共享變量的寫入什麼時候對另外一個線程可見。內存模型定義了線程和主內存之間的抽象關係:線程之間的共享變量存儲在主內存中,每一個線程都有一個私有的本地內存,本地內存中存儲了該線程以讀/寫共享變量的副本。本地內存是內存模型的一個抽象概念,並不真實存在。它涵蓋了緩存,寫緩衝區,寄存器以及其餘的硬件和編譯器優化。緩存

  若是AB兩個線程之間須要相互通訊,多線程

    首先,線程A把本地內存A中更新過的共享變量刷新到主內存中去。併發

    而後,線程B到主內存中去讀取線程A以前已更新過的共享變量。性能

  內存模型經過控制主內存與每一個線程的本地內存之間的交互,來提供內存可見性保證。優化

  2.重排序spa

  在執行程序時爲了提升性能,編譯器和處理器經常會對指令作重排序。線程

    編譯器優化的重排序。編譯器在不改變單線程程序語義的前提下,能夠從新安排語句的執行順序。排序

    指令級並行的重排序。現代處理器採用了指令級並行技術來將多條指令重疊執行。若是不存在數據依賴性,處理器能夠改變語句對應機器指令的執行順序。

    內存系統的重排序。因爲處理器使用緩存和讀/寫緩衝區,這使得加載和存儲操做看上去多是在亂序執行。

  從java源代碼到最終實際執行的指令序列,會分別經歷下面三種重排序:

    源代碼 -- 編譯器優化重排序 -- 指令級並行重排序 -- 內存系統重排序 -- 最終執行

  3.數據競爭

  在業務程序執行時,當存在數據共享時,在代碼實際執行之時,咱們並不能保證徹底按照咱們所寫的代碼語句順序的執行(沒有lock的狀況下)。大多數多線程出現問題的地方在於,咱們並不知道咱們讀取到的是否是咱們原先但願處理的數據,有可能咱們但願發生的修改尚未發生,或者咱們但願讀取到的數據已經被別的線程修改過了。

  4.總線事務

  在計算機中,數據經過總線在處理器和內存之間傳遞。每次處理器和內存之間的數據傳遞都是經過一系列步驟來完成的,這一系列步驟稱之爲總線事務。總線事務包括讀事務和寫事務。讀事務從內存傳送數據處處理器,寫事務從處理器傳送數據到內存,每一個事務會讀/寫內存中一個或多個物理上連續的字。這裏的關鍵是,總線會同步試圖併發使用總線的事務。在一個處理器執行總線事務期間,總線會禁止其它全部的處理器和I/O設備執行內存的讀/寫。在任意時間點,最多隻能有一個處理器能訪問內存。這個特性確保了單個總線事務之中的內存讀/寫操做具備原子性。

  java語言規範鼓勵但不強求JVM對64位的long型變量和double型變量的讀/寫具備原子性。當JVM在這種處理器上運行時,會把一個64位long/ double型變量的讀/寫操做拆分爲兩個32位的讀/寫操做來執行。這兩個32位的讀/寫操做可能會被分配到不一樣的總線事務中執行,此時對這個64位變量的讀/寫將不具備原子性。假設處理器A寫一個long型變量,同時處理器B要讀這個long型變量。處理器A中64位的寫操做被拆分爲兩個32位的寫操做,且這兩個32位的寫操做被分配到不一樣的寫事務中執行。同時處理器B中64位的讀操做被拆分爲兩個32位的讀操做,且這兩個32位的讀操做被分配到同一個的讀事務中執行。當處理器A和B按上圖的時序來執行時,處理器B將看到僅僅被處理器A「寫了一半「的無效值。

相關文章
相關標籤/搜索