Java內存模型java
1 線程之間如何通訊緩存
1.1 共享內存的方式多線程
1.1.1 處理器寫緩存區app
1.1.2 總線jvm
1.1.3 共享內存函數
1.2 消息傳遞的方式優化
1.2.1 線程之間沒有公共狀態,必需經過消息的方式通訊ui
2 從源代碼到指令序列的重排序線程
2.1 重排序分類rest
2.1.1 編譯器優化重排序
2.1.2 處理器重排序
2.1.2.1 內存系統重排序
2.1.2.2 指令級並行重排序
2.2 重排序的影響
2.2.1 單線程中,不影響線程運行結果,給你的幻覺是,它不存在
2.2.2 多線程中,無形中影響運行結果,也是讓人產生錯覺
2.3 禁止特定類型的重排序
2.3.1 內存屏障
2.3.1.1 loadlaod
2.3.1.1.1 load1 loadlaod load2,確保load1數據的裝載先與load2及之後的全部數據裝載指令的執行
2.3.1.2 loadstore
2.3.1.2.1 load1 loadstone store1 確保laod1數據的加載先與store1以及後面全部存儲指令刷新內存
2.3.1.3 storestore
2.3.1.3.1 store1 stroestore store2 確保store1的存儲指令(屬性內存)先有store2以及後面的全部存儲指令的刷新內存
2.3.1.4 storelaod
2.3.1.4.1 store storeload load store 確保store的存儲指令先與load以及後面全部的裝載操做
2.4 單線程的重排序 as-if-serial
2.4.1 單線程在不改變運行結果的狀況下,多有的 編譯器,runtime,處理器都會遵循as-if-serial語義進行重排序
3 數據競爭
3.1 一個線程在寫一個變量,另一個線程在讀一個變量,而兩個線程沒有經過同步來排序
4 順序一致性
4.1 科學家意淫出來的模型
4.2 多個線程按順序執行、單個線程內部按指令順序執行
5 JMM中的順序一致性
5.1 多個線程按照順序執行,邊界內部重排序執行
5.2 long與double型數據寫操做不具有原子性
5.2.1 在計算機中,數據經過總線在處理器與內存中交互。每次交互的多個操做,稱做一個總線事務,而總線會同步事務,一個時刻,只有一個線程與內存交互,串行化了多個處理器對內存的訪問,在某些處理器中,要保證64位數據的寫操做會有比較大的開銷,這樣,妥協以後,java內存模型,鼓勵可是不強求jvm對64位long和double具備原子操做,這樣一次寫,會落在兩個事務中,此時就不具備原子性了
6 volatile的內存語義
6.1 volatile特性
6.1.1 內存可見性
6.1.2 操做原子性
6.2 volatile內存語義
6.2.1 寫時,JMM會把對應線程的本地緩存刷新到內存中
6.2.1.1 寫前,加一個storestore
6.2.1.2 寫後,加一個storeload
6.2.2 讀時,JMM會把對應線程會本地緩存置爲無效,從新裝載內存數據
6.2.2.1 讀後,加一個loadload
6.2.2.2 讀後,加一個loadstore
7 鎖的內存語義
7.1 get鎖時,JMM會把內存的本地緩存置爲無效
7.2 release鎖時,JMM會把對應線程的內存刷到內存中
7.3 ReentrantLock的源碼實現
7.3.1 重人鎖中,組合了一個Sync的對象,這個對象繼承了AbstracQueueSynchronizer對象,acquire與release兩個方法,AQS對象經過volatile來實現鎖的控制
8 Concurrent包的實現
8.1 套路
8.1.1 申明共享變量volatile
8.1.2 用CAS來更新實現線程之間的同步
8.1.3 陪volatile的讀寫與CAS的內存語義,實現內存間通訊
9 final內存語義
9.1 寫時的重排序規則:JMM禁止編譯器把final域的寫重排序到構造函數以外,也就是說,在引用對象被其餘線程可見以前,final域已經被初始化
9.1.1 寫操做以後,有storestore
9.2 讀時的重排序規則:在一個線程中,初次讀對象引用與初次讀該對象包含的final域,這兩個操做,不容許重排序。也就是說,在讀這個final域以前,必定得要先讀這個對象引用
9.2.1 讀操做以前,有loadload
10 對象逸出
10.1 對象在一個線程中,沒有徹底初始化好了以前,就被其餘線程引用,這就是說,這個對象在構造函數中「逸出」。
10.2 對象「逸出」,致使final域的值兩次讀的不同,第一次讀的時候,由於引用對象還沒完成初始化好,final域也還沒執行。第二次讀的時候,final域已經執行完了
11 happens-before
11.1 JMM對於編譯器,處理器沒有啥特別的要求,惟一要求的就是,在不改變程序的運行結果的前提下,你愛怎麼玩就怎麼玩,我無論
11.2 定義
11.2.1 一個操做happens-before另一個操做,那麼第一個操做的執行結果將對第二個操做可見