重排序是指編譯器和處理器爲了優化程序性能而對指令序列進行從新排序的一種手段。
重排序分3種類型。java
這些重排序可能會致使線程程序出現內存可見性問題。
比方,一個線程執行兩行代碼:a = 1; flag = true; 而另一個線程執行if(flag){ a = 2 }。若是前者線程發生重排序,併發的時候後者線程就可能發生線程安全問題。(原本前者線程執行到a=1的時候flag仍是false呢,結果因爲重排序先執行了,就致使後者線程進入了if(){}中)程序員
順序一致性內存模型是一個被計算機科學家理想化了的理論參考模型,它爲程序員提供了極強的內存可見性保證。
順序一致性內存模型有兩大特性。數據庫
在概念上,順序一致性模型有一個單一的全局內存,這個內存經過一個左右擺動的開關能夠鏈接到任意一個線程,同時每個線程必須按照程序的順序來執行內存讀/寫操做,在任意時間點最多隻能有一個線程能夠鏈接到內存。當多個線程併發執行時,全部線程的全部內存讀/寫操做按照調度執行串行化。編程
須要重點理解的happens-before:
爲了不java程序員理解複雜的跟cpu指令相關的內存屏障來保證重排序規則,java使用了happens-before的概念來闡述操做之間的內存可見性。在JMM中,若是一個操做執行的結果須要對另外一個操做可見,那麼兩個操做之間必需要存在happens-before的關係。這兩個操做能夠在同一個線程內,也能夠在不一樣線程內。緩存
happens-before規則:安全
怎麼理解呢?
把A happens-before B 當作 A的發生B必定是知道的。(不是說多線程中A必定要在B以前發生)多線程
什麼是可見性?
各個線程雖然有本身的緩存,但各個線程在使用同一個變量進行運算以前以及運算完成以後,該變量在各個線程中的數據是一致的。併發
什麼是原子性?
原子性其實就是告訴cpu不能中斷,直到執行完一段指令集以後才能切換。cpu執行完時間片後的任意一個原子指令集以後,都有可能被調度器切換到去執行其餘線程。屬於執行的最小單元。相似於數據庫事務的原子性。
數據在主內存與線程工做內存的交互,Java虛擬機規範定義了8種原子操做:鎖定(lock)、解鎖(unlock)、讀取(read)、載入(load)、使用(use)、賦值(assign)、存儲(store)、寫入(write)。
讀取(read)、載入(load)、使用(use)、賦值(assign)、存儲(store)、寫入(write)這6中操做是最基本的原子性操做。 若是想要實現更多操做組成的原子性操做,可使用關鍵字lock和unlock或者synchronized。app
cpu原子性的實現方式:性能
java原子性的實現方式:
循環CAS方式的特色,在低爭搶的場景下,操做效率高。缺點也很明顯:
voliatile關鍵字只保證變量的可見性,禁止指令重排序優化,不是原子性的。
實現可見性的關鍵字有:voliatile、synchronized(lock)、final
保證有序性的關鍵字有:voliatile、synchronized(lock)
參考資料: