高階java必須清楚的概念:原子性、可見性、有序性

茅坤寶駿氹發表於2018-05-02

轉載自 高階java必須清楚的概念:原子性、可見性、有序性


原子性、可見性、有序性是多執行緒程式設計中最重要的幾個知識點,由於多執行緒情況複雜,如何讓每個執行緒能看到正確的結果,這是非常重要的。


原子性


原子性是指一個執行緒的操作是不能被其他執行緒打斷,同一時間只有一個執行緒對一個變數進行操作。在多執行緒情況下,每個執行緒的執行結果不受其他執行緒的干擾,比如說多個執行緒同時對同一個共享成員變數n++100次,如果n初始值為0,n最後的值應該是100,所以說它們是互不干擾的,這就是傳說的中的原子性。但n++並不是原子性的操作,要使用AtomicInteger保證原子性。


可見性


可見性是指某個執行緒修改了某一個共享變數的值,而其他執行緒是否可以看見該共享變數修改後的值。在單執行緒中肯定不會有這種問題,單執行緒讀到的肯定都是最新的值,而在多執行緒程式設計中就不一定了。


每個執行緒都有自己的工作記憶體,執行緒先把共享變數的值從主記憶體讀到工作記憶體,形成一個副本,當計算完後再把副本的值刷回主記憶體,從讀取到最後刷回主記憶體這是一個過程,當還沒刷回主記憶體的時候這時候對其他執行緒是不可見的,所以其他執行緒從主記憶體讀到的值是修改之前的舊值。


像CPU的快取優化、硬體優化、指令重排及對JVM編譯器的優化,都會出現可見性的問題。


有序性


我們都知道程式是按程式碼順序執行的,對於單執行緒來說確實是如此,但在多執行緒情況下就不是如此了。為了優化程式執行和提高CPU的處理效能,JVM和作業系統都會對指令進行重排,也就說前面的程式碼並不一定都會在後面的程式碼前面執行,即後面的程式碼可能會插到前面的程式碼之前執行,只要不影響當前執行緒的執行結果。所以,指令重排只會保證當前執行緒執行結果一致,但指令重排後勢必會影響多執行緒的執行結果。


雖然重排序優化了效能,但也是會遵守一些規則的,並不能隨便亂排序,只是重排序會影響多執行緒執行的結果。



相關文章