亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Java > 正文

Java并發編程- 內存模型詳解

2019-11-06 06:18:27
字體:
來源:轉載
供稿:網友

本文分為四個部分來講解:

java內存模型的基礎, 主要介紹內存模型相關的基本概念;Java內存模型中的順序一致性, 主要介紹重排序與順序一致性內存模型;同步原語, 主要介紹三個同步原語(synchronized, volatile, final)的內存語義及重排序規則在處理器中的實現;Java內存模型的設計, 主要介紹Java內存模型的設計原理, 及其與處理器內存模型和順序一致性內存模型的關系;

Java內存模型基礎

并發編程模型的兩個關鍵問題

線程之間如何通信;線程之間如何同步;

線程通信機制主要有兩種: 共享內存和消息傳遞. Java的并發采用的是共享內存模型.

Java內存模型(JMM)的抽象結構

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

JMM定義了線程和主內存(Main Memory)之間的抽象關系, 屬于語言級的內存模型:

線程之間的共享變量存儲在主內存中, 每個線程又有一個私有的本地內存(Local Memory, 實際上就是Java虛擬機棧, 寄存器, 處理器高速緩存等), 本地內存中存儲了該線程已操作過的共享變量的副本. 本地內存是JMM的一個抽象概念, 并不真實存在, 因為它涵蓋了緩存, 寫緩沖區, 寄存器及其他硬件和編譯器的諸多優化的集合.

如果線程A和線程B要通信的話, 必須要經歷下面兩個步驟:

線程A把本地內存更新過的共享變量刷新到主內存中;線程B到主內存去讀取線程A之前已更新過的共享變量.

可以看出, JMM通過控制主內存和每個線程的本地內存(包含緩存, 寄存器等等)之間的交互, 來為Java程序提供內存可見性的保證.

從源代碼到指令序列的重排序

重排序主要是為了提高性能, 通常分為三種:

編譯器優化的重排序. 原則是在不改變單線程程序語義的前提下, 重新安排語句的執行順序;指令級并行的重排序. 在不存在數據依賴性的時候, 處理器可以改變語句對應的機器指令的執行順序, 甚至并行執行指令;內存系統的重排序. 由于處理器使用高速緩存和讀/寫緩沖區, 這使得加載和存儲操作看上去可能是在亂序執行.

Java從源代碼到最終執行的指令序列, 會依次進行以上三種重排序. 其中1屬于編譯器重排序, 2和3屬于處理器重排序. 重排序會導致內存可見性的問題. JMM通過設定重排序規則, 禁止特定的編譯器重排序, 對于處理器重排序, 則是通過插入特定類型的內存屏障(Memory Barriers)指令, 來禁止特定類型的處理器重排序, 以確保在不同編譯器和處理器平臺下, 始終能為程序員提供一致的內存可見性保證.

內存屏障類型表

注意: 內存屏障要特別注意Store類型的屏障, 每個Store類型的屏障都對應著將線程私有的寫緩沖寫回到主存的操作, 也就是實現線程間可見性的操作

內存屏障實際上是通過限制單線程內指令的重排序來作用的.

JMM將內存屏障指令分為4種類型:

屏障類型 指令示例 說明
LoadLoad Barriers Load1; LoadLoad; Load2 確保Load1數據的裝載先于Load2指令的裝載(load2的裝載是本線程內部的狀態,其他線程的決定不了)
StoreStore Barriers Store1; StoreStore; Store2 確保Store1數據對其它處理器可見(將Store1及之前的Store操作數據刷入主內存中)先于Store2的存儲(store2的存儲是本線程內部的存儲, 其他線程的存儲決定不了)
LoadStore Barriers Load1; LoadStore; Store2 確保Load1數據的裝載先于Store2的存儲(store2的存儲是本線程內部的存儲, 其他線程的存儲決定不了)
StoreLoad Barriers Store1; StoreLoad; Load2 確保Store1數據對其它處理器可見(將Store1及之前的Store操作刷入主內存中)先于Load2的裝載(load2的裝載發生在線程私有內存內部)

其中, StoreLoad屏障是一個全能屏障, 因為它包含了其他所有屏障的效果, 但是開銷大, 因為要把寫緩沖區的所有數據全部刷新到內存中.

happens-before簡介

在JMM中, 如果一個操作執行的結果要對另一個操作可見(通常指的是數據依賴性), 那么這兩個操作之間必須要存在happens-before關系. 主要有以下規則:

程序順序規則: 單線程中的某操作, happens-before于對其有數據依賴性的操作;監視器鎖規則: 對一個鎖的解鎖, happens-before于隨后對這個鎖的加鎖;volatile變量規則: 對一個volatile域的寫, happens-before于后續對這個域的讀(實質上是通過緩存鎖定的LOCK信號來實現的); 使所有處理器的相應地址的緩存行失效, 強制重新從共享主存中讀取. 而且不允許兩個線程同時更改同一個緩存行傳遞性: A happens-before B happens-before C, 則 A happens-before C

重排序

重排序遵守一個統一的原則, 就是讓重排序后的程序至少能夠在單線程的情況下正確運行(意思是在單線程下和重排序前的運行結果相同).

順序一致性

即所有操作具有全序關系, 是一個理想化的模型. 但是JMM天然并不能保證順序一致性, 需要通過同步原語(Synchronized, volatile, final)來輔助完成.

volatile的內存語義

volatile作用于一個filed上, 能夠確保它的可見性. 例如, 現在有一個filed名為l, 我們定義PRivate volatile long l, 就相當于定義:

private long l;public synchronized long get() { return this.l;}public synchronized set(long l) { this.l = l;}

volatile寫-讀與內存屏障

從內存語義的角度來說, volatile的寫和鎖的釋放有相同的內存語義; volatile的讀與鎖的獲取有相同的語義.

volatile底層實際上是通過內存屏障的方式來確保了可見性, 以下是volatile附近的內存屏障的情況:

在每個volatile寫操作的前面插入一個StoreStore屏障;在每個volatile寫操作的后面插入一個StoreLoad屏障;在每個volatile讀操作后面插入一個LoadLoad屏障;在每個volatile讀操作后面插入一個LoadStore屏障;

實際使用中volatile常用做if或者循環的標識位.

定義成volatile的變量, 能夠在線程間保持可見性, 能夠被多線程同時讀(注意: 內存屏障只是限制了單線程內的語句排序), 但是同時只能被一個線程寫.

鎖的內存語義

當線程釋放鎖時, JMM會把該線程對應的本地內存中的共享變量刷新到主內存中去; 當線程獲取鎖時, JMM會把該線程對應的本地內存置為無效, 臨界區代碼必須從主內存重新讀取共享變量;

在底層的實現上

在鎖的釋放上, 公平鎖和非公平鎖最后都需要寫一個volatile變量state;在鎖的獲取時, 公平鎖會讀volatile變量, 非公平鎖會用CAS更新volatile變量.

所以鎖的釋放與volatile的寫, 鎖的獲取同時具有volatile讀寫的語義.

concurrent包的實現

concurrent包的基礎就是volatile變量的讀/寫, 以及CAS. CAS兼具volatile變量讀寫的內存語義

final域的內存語義

final域的寫之后, 會插入一個StoreStore屏障final域的讀之前, 會插入一個LoadLoad屏障

只要被構造的對象的引用在構造函數中沒有逸出, 那么基于上述兩條規則, 就不需要使用同步, 就可以保證任意線程都能看到這個final域在構造函數中被初始化之后的值. 如果逸出了, 那么可能會引起重排序, 導致引用在final域初始化之前被其他線程獲取, 導致獲得未經初始化的final域的值.

happens-before

最實用的三種happens-before

1. volatile寫, happens-before后續volatile讀;

volatile-happens-before

以下是一個例子:

/*** 下面一段語句, 能夠保證1 happens before 4, 也就是無論運行多少次, 結果都輸出100** <p>所以結論是, volatile變量非常適合作為循環的標識位.** Created by yihao.cong@Outlook.com on 16-11-4.*/public class VolatileHappensBefore {private volatile static boolean ready = true;private static int number = 1;private static class ReaderThread extends Thread { @Override public void run() { // 3. 子線程讀volatile變量 while (VolatileHappensBefore.ready) { // 這里是LoadLoad+LoadStore屏障 } // 這里是LoadLoad+LoadStore屏障 // 4. 子線程讀共享變量 out.println(VolatileHappensBefore.number); }}public static void main(String[] args) throws InterruptedException { ReaderThread readerThread = new ReaderThread(); readerThread.start(); Thread.sleep(100); /*下面語句復現的是volatile寫讀的happens-before規則*/ // 1. 主線程修改共享變量 VolatileHappensBefore.number = 100; // 這里是StoreStore屏障 // 2. 主線程寫volatile變量 VolatileHappensBefore.ready = false; // 這里是StoreLoad屏障 // 如此一來能夠保證只要volatile變量的修改能夠讀到, 那么之前的修改一定能夠被讀到}}

2. start()規則: 如果線程A執行操作ThreadB.start(), 那么線程AThreadB.start()操作happens-before線程B中的任何操作;

thread-start-happens-before

3. join()規則: 如果線程A執行操作ThreadB.join()并成功返回, 那么線程B中的任意操作happens-before與線程A在ThreadB.join()操作的成功返回.

thread-join-happens-before

單例模式 - 雙重檢查鎖定與延遲初始化

雙重檢查鎖定其實是錯誤的, 因為可能一個實例還沒有被完全初始化, 就返回了引用. 導致外層的檢查失效, 使得其他線程獲得一個不完整的對象引用.

替代方案1: 使用volatile關鍵字修飾單例對象, 確保可見性, 不會讓寫了一半的對象被其他線程讀到; 替代方案2: 基于類的初始化方案; 替代方案3(推薦): 使用enum進行單例的初始化;

總結

CAS操作同時具有volatile的讀寫語義, 也就是之前之后的代碼都不能重排序. 底層是通過一個lock指令, 進行緩存鎖定, 確保讀-改-寫操作的原子性.緩存一致性和緩存鎖定說的是同一件事, 都是lock指令造成的緩存鎖定(或者說獨占僅那一個地址的主存和緩存).只有volatile寫操作或者是CAS(一種內置的復合操作)才會觸發lock
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
成人免费视频在线观看超级碰| 国产精品88a∨| 97成人精品视频在线观看| 欧美国产日韩一区二区在线观看| 欧美视频免费在线| 2021久久精品国产99国产精品| 亚洲第一级黄色片| 国产精品视频一| 亚洲男人天堂2024| 欧美激情一级欧美精品| 欧美肥老太性生活视频| 操91在线视频| 亚洲精品影视在线观看| 久久电影一区二区| 日本精品一区二区三区在线| 成人网在线免费观看| 日韩成人av在线| 亚洲高清免费观看高清完整版| 国产精品久久中文| 欧美午夜精品久久久久久浪潮| 精品国偷自产在线视频| 亚洲精品久久久久久下一站| 日韩电影免费观看中文字幕| 亚洲国产成人精品女人久久久| 亚洲高清久久网| 欧美精品久久一区二区| 亚洲精品久久久久久久久久久| 2019中文字幕在线免费观看| 欧美性精品220| 精品视频久久久| 国产成+人+综合+亚洲欧洲| 中文字幕精品久久久久| 欧美一级淫片丝袜脚交| 久久99热精品这里久久精品| 国产精品第100页| 国产91ⅴ在线精品免费观看| 亚洲一区中文字幕| 最近2019年日本中文免费字幕| 美女黄色丝袜一区| 中文字幕欧美日韩精品| 欧美黑人巨大xxx极品| 久久亚洲成人精品| 欧美视频一区二区三区…| 日韩国产一区三区| 日韩av手机在线观看| 欧美一区视频在线| 这里只有精品久久| 日韩精品极品在线观看播放免费视频| 美女福利视频一区| 精品中文字幕在线| 亚洲成人网久久久| 日韩69视频在线观看| 亚洲在线视频观看| 亚洲欧美激情精品一区二区| 亚洲美女视频网站| 亚洲男人天堂2024| 日韩中文字幕av| 精品久久久久久国产91| 韩国精品美女www爽爽爽视频| 久久久精品视频成人| 久久久av亚洲男天堂| 久久免费视频在线观看| 福利二区91精品bt7086| 成人精品一区二区三区电影黑人| 日韩欧美精品网址| 琪琪亚洲精品午夜在线| 日韩视频一区在线| 九九久久综合网站| 国产精品99久久久久久白浆小说| 亚洲一区二区三区777| 国产精品国产三级国产aⅴ9色| 国产精品久久久久久久久影视| 国产精品啪视频| 亚洲网站在线观看| 这里只有精品在线观看| 91天堂在线观看| 国产欧美精品xxxx另类| 97视频在线观看免费| 9.1国产丝袜在线观看| 国产精品嫩草影院久久久| 久久免费视频在线观看| 国产一区二区三区在线看| 亚洲第一区中文字幕| 成人国产精品久久久久久亚洲| 欧美日产国产成人免费图片| 欧美激情aaaa| 性色av香蕉一区二区| 国产精品高潮视频| 欧美亚洲另类激情另类| 亚洲的天堂在线中文字幕| 日韩高清有码在线| 欧美激情一级精品国产| 国产成人精品亚洲精品| 一区二区在线免费视频| 色999日韩欧美国产| 久久在线精品视频| 欧美电影在线观看网站| 国产成人精品视频在线| 国产精品久久不能| 精品亚洲va在线va天堂资源站| 欧美日韩在线视频一区二区| 久久久久久久久久久网站| 91久久精品国产91久久性色| 亚洲女人被黑人巨大进入| 日韩经典中文字幕在线观看| 欧美性videos高清精品| 久久成人综合视频| 国产日韩av高清| 91久久精品久久国产性色也91| 国产精品毛片a∨一区二区三区|国| 国产精品视频999| 国产精品成人一区二区三区吃奶| 日韩视频免费大全中文字幕| 亚洲黄色av女优在线观看| 成人激情在线播放| 黑人巨大精品欧美一区二区免费| 国产精品视频免费观看www| 亚洲日本中文字幕| 热99久久精品| 国产精品老女人精品视频| 精品一区二区电影| 亚洲自拍偷拍一区| 日韩中文字幕网| 1769国产精品| 国产精品夫妻激情| 久久躁狠狠躁夜夜爽| 国产欧美日韩视频| 国产一区二区三区免费视频| 成人有码视频在线播放| 亚洲精品98久久久久久中文字幕| 不卡在线观看电视剧完整版| 日韩精品视频在线观看免费| 欧美在线视频一二三| 国产精品视频自在线| 中文字幕精品—区二区| 亚洲国产日韩欧美在线动漫| 成人看片人aa| 国产精品6699| 色噜噜狠狠色综合网图区| 91九色视频导航| 欧美国产日本高清在线| 亚洲成年人在线播放| 亚洲黄一区二区| 久久精品久久久久久| 久国内精品在线| 国产亚洲激情视频在线| 亚洲人线精品午夜| 日韩欧美高清在线视频| 欧美一区二区三区免费观看| 美女福利精品视频| 岛国av在线不卡| 久久久久久av| 国产午夜精品理论片a级探花| 欧美性猛交xxxxx免费看| 国产精品爽爽爽爽爽爽在线观看| 国产一区二区三区高清在线观看| 一区二区三区视频观看| 日韩国产精品一区| 国产视频精品免费播放| 夜色77av精品影院| 51ⅴ精品国产91久久久久久| 国产精品一区二区久久久久| 日韩视频―中文字幕| 国产精品久久久久国产a级|