java並發學習--第九章 指令重排序


一、happns-before

  happns-before是學習指令重排序前的一個必須了解的知識點,他的作用主要是就是用來判斷代碼的執行順序。

  1.定義

  happens-before是用來指定兩個操作之間的執行順序。提供跨線程的內存可見性。

  在java內存模型中,如果一個操作執行的結果需要對另一個操作可見,那么這兩個操作之間必然存在happens-before關系

  2.happens-before規則

  a.程序順序規則

  單線程中的每個操作,總是前一個操作happens-before於該線程中的任意后續操作。

  簡單的說,這個規則就是代碼按照順序執行。 

 

  b.監視器規則

  對一個鎖的解鎖,總是happens-before於隨后對這個鎖的加鎖。

  這句話可以理解成對於同一把鎖,釋放與獲取是線程可見的;釋放鎖的操作總是happens-before於獲取鎖的操作

 

  c.volatile變量規則

  對一個volatile域的寫總是happens-before於任意后續對這個volatile域的讀。

  就是說被volatile修飾的變量,在線程中是是可見的。

 

  d.傳遞性

  這個規則與程序性規則相識:有A、B、C三變量,如果根據程序性規則:

    A變量 happens-before B變量,

    B變量 happens-before C變量,

    則必然有

    A變量 happens-before C變量。

 

  f.start規則

  這個規則是在多線程場景中會經常出現的:A線程中調用了B線程,那么A線程happens-before於B線程。

  或者說A線程的結果對B線程是可見的(結果必須在調用B線程前就已經出現)。

 

  g.join規則

  多線程場景中,如果有線程使用了join方法,那么join的線程一點是happens-before於調用的線程。

 二、指令重排序

  了解過happens-before后,終於可以進入本結的主題了指令重排序。

  1.定義

  我們知道jvm運行的是java文件編譯后的字節碼指令,編譯器為了優化程序的性能,會重新對字節碼指令排序,雖然會重排序,但是指令重排序運行的結果一定是正常的。

  2.數據的依賴性

  能夠進行指令重排序的地方,就是看這個段代碼的數據依賴性,有三種情況是不能夠進行指令重排序的:

  ①對某個對象或者變量,先進行賦值再讀這個對象的值(寫后讀)

  ②對某個對象或者變量,先讀這個對象的值再對這個對象賦值(讀后寫)

  ③對某個對象或者變量,先后進行了兩次賦值(寫后寫)

  如果對這三種情況進行指令重排序的話,獲得的結果一定是錯誤的。所以規定在這三種情況中,是不能進行指令重排序。

  3.指令重排序所帶來的影響

  指令重排序一共分為兩種情況:

  a.編譯器重排序

  b.處理器重排序(這個必須是在多個CPU情況下才會發生)

  指令重排序在單線程中對我們程序的幫助一定是正向的,它能夠很好的優化我們程序的性能。但是在多線程情況下,就不一定了,但是出現指令重排序情況導致線程安全性問題的情況都是很少見的,就算出現也是很難去發現的。最簡單的例子:雙檢查鎖單例模式。如果出現了由於指令重排序造成的線程安全性問題,就可以使用volatile關鍵字來解決。

  

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM