日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術(shù)文章
文章詳情頁

Java并發(fā)編程-volatile

瀏覽:146日期:2022-09-05 13:15:25

上一篇文章,學(xué)習(xí)了并發(fā)編程中的synchronized,這個(gè)比較好理解,也是我最初學(xué)習(xí)多線程編程中的一個(gè)簡單的實(shí)現(xiàn)的,大學(xué)的時(shí)候就會(huì)了,然后就一直以為多線程環(huán)境的同步只能通過這個(gè)來實(shí)現(xiàn)的,事實(shí)上Java還提供了另外一個(gè)更加輕量級(jí)的實(shí)現(xiàn)-volatile,如果說synchronized實(shí)現(xiàn)了數(shù)據(jù)在同一時(shí)刻只能有一個(gè)線程對(duì)數(shù)據(jù)訪問的話,那么volatile實(shí)現(xiàn)的就是同時(shí)可以多個(gè)線程在訪問數(shù)據(jù),但是只要數(shù)據(jù)發(fā)生了變化,便確保其他線程及時(shí)“感知”這種變化。

1、 CPU 、主存及高速緩存的概念

計(jì)算機(jī)的硬件組成可以抽象為由總線、IO設(shè)備、主存、處理器(CPU)等組成。其中數(shù)據(jù)存放在主存中,CPU負(fù)責(zé)指令的執(zhí)行,CPU的指令執(zhí)行非常快,大部分簡單指令的執(zhí)行只需要一個(gè)時(shí)鐘周期,而一次主內(nèi)存數(shù)據(jù)的讀取則需要幾十到幾百個(gè)時(shí)鐘周期,那么CPU從主存中讀寫數(shù)據(jù)就會(huì)有很大的延遲。這個(gè)時(shí)候就產(chǎn)生了高速緩存的概念。

也就是說,當(dāng)程序在運(yùn)行過程中,會(huì)將運(yùn)算需要的數(shù)據(jù)從主存復(fù)制一份到CPU的高速緩存當(dāng)中,那么CPU進(jìn)行計(jì)算時(shí)就可以直接從它的高速緩存讀取數(shù)據(jù)和向其中寫入數(shù)據(jù),當(dāng)運(yùn)算結(jié)束之后,再將高速緩存中的數(shù)據(jù)回寫到主存當(dāng)中,通過這種方式來降低CPU從主存中獲取數(shù)據(jù)的延遲。大致的示意圖如下:

Java并發(fā)編程-volatile

圖一這個(gè)模型,可以簡單的認(rèn)為是單核模型,在這個(gè)模型里面,以i++這個(gè)操作為例,程序執(zhí)行時(shí),會(huì)先從主內(nèi)存中獲取i的值,復(fù)制到高速緩存,然后CPU從高速緩存中加載并執(zhí)行+1操作,操作完成后回寫到高速緩存,最后再從高速緩存回寫到主內(nèi)存。單核模型這樣操作沒有任何問題,但是計(jì)算機(jī)自產(chǎn)生以來,一直追求的兩個(gè)目標(biāo),一個(gè)是如何做的更多,另一個(gè)就是如何計(jì)算得更快,這樣帶來的變化就是單核變成多核,高速緩存分級(jí)存儲(chǔ)。大致的示意圖如下:

Java并發(fā)編程-volatile

在圖二示意圖里面,i++這個(gè)操作就有問題了,因?yàn)槎嗪薈PU可以線程并行計(jì)算,在Core 0和Core 1中可以同時(shí)將i復(fù)制到各自緩存中,然后CPU各自進(jìn)行計(jì)算,假設(shè)初始i為1,那么預(yù)期我們希望是2,但是實(shí)際由于兩個(gè)CPU各自先后計(jì)算后最終主內(nèi)存中的i可能是2,也可能是其他值。

這個(gè)就是硬件內(nèi)存架構(gòu)中存在的一個(gè)問題,緩存一致性問題,就是說核1改變了變量i的值之后,核0是不知道的,存放的還是舊值,最終對(duì)這樣的一個(gè)臟數(shù)據(jù)進(jìn)行操作。

為此,CPU的廠商定制了相關(guān)的規(guī)則來解決這樣一個(gè)硬件問題,主要有如下方式:

1) 總線加鎖,其實(shí)很好理解總線鎖,咱們來看圖二,前面提到了變量會(huì)從主內(nèi)存復(fù)制到高速緩存,計(jì)算完成后,會(huì)再回寫到主內(nèi)存,而高速緩存和主內(nèi)存的交互是會(huì)經(jīng)過總線的。既然變量在同一時(shí)刻不能被多個(gè)CPU同時(shí)操作,會(huì)帶來臟數(shù)據(jù),那么只要在總線上阻塞其他CPU,確保同一時(shí)刻只能有一個(gè)CPU對(duì)變量進(jìn)行操作,后續(xù)的CPU讀寫操作就不會(huì)有臟數(shù)據(jù)。總線鎖的缺點(diǎn)也很明顯,有點(diǎn)類似將多核操作變成單核操作,所以效率低;

2) 緩存鎖,即緩存一致性協(xié)議,主要有MSI、MESI、MOSI等,這些協(xié)議的主要核心思想:當(dāng)CPU寫數(shù)據(jù)時(shí),如果發(fā)現(xiàn)操作的變量是共享變量,即在其他CPU中也存在該變量的副本,會(huì)發(fā)出信號(hào)通知其他CPU將該變量的緩存行置為無效狀態(tài),因此當(dāng)其他CPU需要讀取這個(gè)變量時(shí),發(fā)現(xiàn)自己緩存中緩存該變量的緩存行是無效的,那么它就會(huì)從內(nèi)存重新讀取。

2、 Java 內(nèi)存模型

在Java虛擬機(jī)規(guī)范中試圖定義一種Java內(nèi)存模型(Java Memory Model,JMM)來屏蔽各個(gè)硬件平臺(tái)和操作系統(tǒng)的內(nèi)存訪問差異,以實(shí)現(xiàn)讓Java程序在各種平臺(tái)下都能達(dá)到一致的內(nèi)存訪問效果。在此之前,主流程序語言(C/C++等)直接使用物理硬件和操作系統(tǒng)的內(nèi)存模型(可以理解為類似于直接使用了硬件標(biāo)準(zhǔn)),都或多或少的在不同的平臺(tái)有著不一樣的執(zhí)行結(jié)果。

Java內(nèi)存模型的主要目標(biāo)是定義程序中各個(gè)變量的訪問規(guī)則,即變量在內(nèi)存中的存儲(chǔ)和從內(nèi)存中取出變量這樣的底層細(xì)節(jié)。其規(guī)定了所有變量都存儲(chǔ)在主內(nèi)存,每個(gè)線程還有自己的工作內(nèi)存,線程讀寫變量時(shí)需先復(fù)制到工作內(nèi)存,執(zhí)行完計(jì)算操作后再回寫到主內(nèi)存,每個(gè)線程還不能訪問其他線程的工作內(nèi)存。大致示意圖如下:

Java并發(fā)編程-volatile

圖三我們可以理解為和圖二表達(dá)的是一個(gè)意思,工作內(nèi)存可以看成是CPU高速緩存、寄存器的抽象,主內(nèi)存可以看成就是物理硬件中主內(nèi)存的抽象,圖二這個(gè)模型會(huì)存在緩存一致性問題,圖三同樣也會(huì)存在緩存一致性問題。

另外,為了獲得較好的執(zhí)行性能,Java內(nèi)存模型并沒有限制執(zhí)行引擎使用處理器的寄存器或者高速緩存來提升指令執(zhí)行速度,也沒有限制編譯器對(duì)指令進(jìn)行重排序。也就是說,在Java內(nèi)存模型中,還會(huì)存在指令重排序的問題。

Java語言又是怎么來解決這兩個(gè)問題的呢?就是通過volatile這個(gè)關(guān)鍵字來解決緩存一致性和指令重排問題,volatile作用就是確保可見性和禁止指令重排。

3 、volatile 背后實(shí)現(xiàn)

那么volatile又是怎樣來確保的可見性和禁止指令重排呢?咱們先來寫一段單例模式代碼來看看。

public class Singleton { private static volatile Singleton instance; public static Singleton getInstance() {if (instance == null) { synchronized (Singleton.class) {if (instance == null) { instance = new Singleton();} }}return instance; } public static void main(String[] args) {Singleton.getInstance(); }}

先看看字節(jié)碼層面,JVM都做了什么。

Java并發(fā)編程-volatile

圖四

從圖四可以看出,沒有什么特別之處。既然在字節(jié)碼層面我們看不出什么端倪,那下面就看看將代碼轉(zhuǎn)換為匯編指令能看出什么端倪。轉(zhuǎn)換為匯編指令,可以通過-XX:+PrintAssembly來實(shí)現(xiàn),window環(huán)境具體如何操作請(qǐng)參考此處(https://dropzone.nfshost.com/hsdis.xht)。不過比較可惜的是我雖然編譯成功了hsdis-i386.dll(圖五),放置在了JDK8下的多個(gè)bin目錄,一致在報(bào)找不到這個(gè)dll文件所以我決定換個(gè)思路一窺究竟。

Java并發(fā)編程-volatile

圖五

這個(gè)思路就是去閱讀openJDK的源代碼。其實(shí)通過javap可以看到volatile字節(jié)碼層面有個(gè)關(guān)鍵字ACC_VOLATILE,通過這個(gè)關(guān)鍵字定位到accessFlags.hpp文件,代碼如下:

bool is_volatile () const { return (_flags & JVM_ACC_VOLATILE ) != 0; }

再搜索關(guān)鍵字is_volatile,在bytecodeInterpreter.cpp可以看到如下代碼:

// // Now store the result // int field_offset = cache->f2_as_index(); if (cache->is_volatile()) { if (tos_type == itos) { obj->release_int_field_put(field_offset, STACK_INT(-1)); } else if (tos_type == atos) { VERIFY_OOP(STACK_OBJECT(-1)); obj->release_obj_field_put(field_offset, STACK_OBJECT(-1)); OrderAccess::release_store(&BYTE_MAP_BASE[(uintptr_t)obj >> CardTableModRefBS::card_shift], 0); } else if (tos_type == btos) { obj->release_byte_field_put(field_offset, STACK_INT(-1)); } else if (tos_type == ltos) { obj->release_long_field_put(field_offset, STACK_LONG(-1)); } else if (tos_type == ctos) { obj->release_char_field_put(field_offset, STACK_INT(-1)); } else if (tos_type == stos) { obj->release_short_field_put(field_offset, STACK_INT(-1)); } else if (tos_type == ftos) { obj->release_float_field_put(field_offset, STACK_FLOAT(-1)); } else { obj->release_double_field_put(field_offset, STACK_DOUBLE(-1)); } OrderAccess::storeload(); }

在這段代碼中,會(huì)先判斷tos_type,后面分別有不同的基礎(chǔ)類型的實(shí)現(xiàn),比如int就調(diào)用release_int_field_put,byte就調(diào)用release_byte_field_put等等。以int類型為例,繼續(xù)搜索方法release_int_field_put,在oop.hpp可以看到如下代碼:

void release_int_field_put(int offset, jint contents);

這段代碼實(shí)際是內(nèi)聯(lián)oop.inline.hpp,具體的實(shí)現(xiàn)是這樣的:

inline void oopDesc::release_int_field_put(int offset, jint contents) { OrderAccess::release_store(int_field_addr(offset), contents); }

其實(shí)看到這,可以看到上一篇文章很熟悉的oop.hpp和oop.inline.hpp,就是很熟悉的Java對(duì)象模型。繼續(xù)看OrderAccess::release_store,可以在orderAccess.hpp找到對(duì)應(yīng)的實(shí)現(xiàn)方法:

static void release_store(volatile jint* p, jint v);

實(shí)際上這個(gè)方法的實(shí)現(xiàn)又有很多內(nèi)聯(lián)的針對(duì)不同的CPU有不同的實(shí)現(xiàn)的,在src/os_cpu目錄下可以看到不同的實(shí)現(xiàn),以orderAccess_linux_x86.inline.hpp為例,是這么實(shí)現(xiàn)的:

inline void OrderAccess::release_store(volatile jint* p, jint v) { *p = v; }

可以看到其實(shí)Java的volatile操作,在JVM實(shí)現(xiàn)層面第一步是給予了C++的原語實(shí)現(xiàn),接下來呢再看bytecodeInterpreter.cpp截取的代碼,會(huì)再給予一個(gè)OrderAccess::storeload()操作,而這個(gè)操作執(zhí)行的代碼是這樣的(orderAccess_linux_x86.inline.hpp):

inline void OrderAccess::storeload() { fence(); }

fence方法代碼如下:

inline void OrderAccess::fence() { if (os::is_MP()) { // always use locked addl since mfence is sometimes expensive#ifdef AMD64 __asm__ volatile ('lock; addl $0,0(%%rsp)' : : : 'cc', 'memory');#else __asm__ volatile ('lock; addl $0,0(%%esp)' : : : 'cc', 'memory');#endif }}

一樣可以看到和通過-XX:+PrintAssembly來看到的背后實(shí)現(xiàn):lock; addl,其實(shí)這個(gè)就是內(nèi)存屏障,關(guān)于內(nèi)存屏障的詳細(xì)說明可以看下orderAccess.hpp的注釋。內(nèi)存屏障提供了3個(gè)功能:確保指令重排序時(shí)不會(huì)把其后面的指令排到內(nèi)存屏障之前的位置,也不會(huì)把前面的指令排到內(nèi)存屏障的后面;強(qiáng)制將對(duì)緩存的修改操作立即寫入主存;如果是寫操作,它會(huì)導(dǎo)致其他CPU中對(duì)應(yīng)的緩存行無效。這3個(gè)功能又是怎么做到的呢?來看下內(nèi)存屏障的策略:

在每個(gè)volatile寫操作前面插入storestore屏障;

在每個(gè)volatile寫操作后面插入storeload屏障;

在每個(gè)volatile讀操作后面插入loadload屏障;

在每個(gè)volatile讀操作后面插入loadstore屏障;

其中l(wèi)oadload和loadstore對(duì)應(yīng)的是方法acquire,storestore對(duì)應(yīng)的是方法release,storeload對(duì)應(yīng)的是方法fence。

4 、volatile 應(yīng)用場景

4.1 double check 單例

public class Singleton { private static volatile Singleton instance; private Singleton() {}; public static Singleton getInstance() {if (instance == null) { synchronized (Singleton.class) {if (instance == null) { instance = new Singleton();} }}return instance; }}

為什么要這樣寫,這個(gè)網(wǎng)上有很多資料,這里就不贅述了。

4.2 java.util.concurrent

大量的應(yīng)用在j.u.c下的各個(gè)基礎(chǔ)類和工具欄,構(gòu)成Java并發(fā)包的基礎(chǔ)。后續(xù)并發(fā)編程的學(xué)習(xí)就可以按照這個(gè)路線圖來學(xué)習(xí)了。

Java并發(fā)編程-volatile

參考資料:

https://github.com/lingjiango/ConcurrentProgramPractice

https://stackoverflow.com/questions/4885570/what-does-volatile-mean-in-java

https://stackoverflow.com/questions/106591/do-you-ever-use-the-volatile-keyword-in-java

https://www.cnblogs.com/zhangj95/p/5647051.html

http://download.oracle.com/otn-pub/jcp/memory_model-1.0-pfd-spec-oth-JSpec

https://www.cs.umd.edu/~pugh/java/memoryModel/

來自:http://www.cnblogs.com/iou123lg/p/9280639.html

標(biāo)簽: Java
相關(guān)文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
亚洲91在线| 日韩免费小视频| 日韩在线欧美| 9999国产精品| 亚洲国产专区校园欧美| 91精品在线观看国产| 久久激情一区| 99国产精品| 日本大胆欧美人术艺术动态| 久久久久国产精品一区二区| 久久精品91| 久久亚洲不卡| 欧美激情福利| 久久久国产亚洲精品| 欧美日韩四区| 国产精品毛片在线| 久久久一二三| 亚久久调教视频| 久久天堂影院| 久久国产亚洲| 久久久久中文| 中文视频一区| 精品国产亚洲一区二区三区大结局| 成人在线视频中文字幕| 97精品在线| 亚洲午夜一级| 欧美精品九九| 亚洲精品综合| 精品国内亚洲2022精品成人| 欧美sss在线视频| 亚洲一区免费| 亚洲精品自拍| 久久久人人人| 亚洲精品乱码久久久久久蜜桃麻豆| 蜜桃精品视频| 欧美一级专区| 日韩啪啪电影网| 自拍日韩欧美| 成人影视亚洲图片在线| 奇米狠狠一区二区三区| 97精品视频在线看| 日韩三级视频| 中文在线一区| 激情视频一区二区三区| 国内精品伊人| 国产精品成人**免费视频| 久久国产成人| 99亚洲视频| 日韩精品永久网址| 麻豆国产91在线播放| 日韩动漫一区| 日本成人手机在线| 日韩不卡在线观看日韩不卡视频 | 亚洲精品少妇| 亚洲黄页一区| 日韩一级精品| 五月天久久网站| 激情欧美一区二区三区| 精品成人免费一区二区在线播放| 国产精品一区二区美女视频免费看| 亚洲精品四区| 911亚洲精品| 国产精品久久久久久av公交车| 欧美一级全黄| 国产精品igao视频网网址不卡日韩| 亚久久调教视频| 国产精品中文字幕制服诱惑| 国产精品久久久免费| 精品一区二区三区在线观看视频| 国产精品国码视频| 高清不卡一区| 欧美va天堂在线| 国产精品嫩草99av在线| 久久aⅴ国产紧身牛仔裤| 国产精品免费看| 亚洲1区在线| 国产精品三上| 中文字幕成在线观看| 日韩一区二区三区四区五区| 蜜桃国内精品久久久久软件9| 国产精品一国产精品| 亚洲尤物在线| 丝袜脚交一区二区| 亚洲精品一区三区三区在线观看| 国产精品成人3p一区二区三区| 国产精品成人自拍| 日韩一区三区| 免费av一区二区三区四区| 三级在线观看一区二区| 日韩高清二区| 成人污污视频| 一区二区三区国产盗摄| 91精品麻豆| 精品中文字幕一区二区三区四区| 国产综合激情| 日韩精品亚洲一区二区三区免费| 免费一级片91| 日韩三级精品| 日韩av免费| 国产一区 二区| 亚洲黑丝一区二区| 日韩一区二区三区免费视频| 精品国产精品久久一区免费式| 久久一区二区中文字幕| 亚洲精品麻豆| 国产精品专区免费| 国产一精品一av一免费爽爽| 国产色综合网| 日韩成人精品一区| 亚洲一区免费| 精品国产aⅴ| 日韩精品三级| 尤物在线精品| 成人台湾亚洲精品一区二区| 一区二区亚洲视频| 91亚洲成人| 国产欧美日韩综合一区在线播放| 午夜在线播放视频欧美| 国产a亚洲精品| 久久激情五月婷婷| 美女黄网久久| 成人欧美一区二区三区的电影| 欧美影院视频| 久久国产三级精品| 日韩精品高清不卡| 国产视频久久| 亚洲欧美视频| 黄色aa久久| 日韩欧美二区| 成人日韩在线| 在线一区视频观看| 国产精品久久久久久久免费软件| 97成人在线| 国产精品老牛| 精品日韩一区| 精品中文字幕一区二区三区| 美女久久精品| 成人在线视频免费看| 国产成人精品一区二区免费看京 | 国产精品s色| 91亚洲一区| 天堂网在线观看国产精品| 国产va免费精品观看精品视频| www.com.cn成人| 国产视频一区在线观看一区免费| 99精品99| 亚洲精品大片| 国产精品分类| 欧美另类中文字幕| 国产不卡精品在线| 国产伦理一区| 国产麻豆一区二区三区精品视频| 麻豆视频观看网址久久| 亚洲精品电影| 亚洲综合电影| 在线国产精品一区| 国产精品高清一区二区| 成人黄色av| 视频精品一区| 天堂日韩电影| 热久久免费视频| 亚洲开心激情| 日韩在线观看不卡| 日韩免费精品| 欧美日韩一区二区综合| 欧美日本不卡| 国产黄大片在线观看| 丝袜美腿一区二区三区| 欧美aa在线视频| 亚洲综合图色| 国产传媒在线观看| 日韩国产高清在线| 精品一二三区| 成人在线网站| 日韩免费精品| 99xxxx成人网| 免费日韩一区二区三区| 亚洲欧美网站| 国产精品网址| 夜夜精品视频| 国产精品流白浆在线观看| 亚洲精品电影| 麻豆理论在线观看| 国产精品自在| 视频一区日韩精品| 日本va欧美va精品发布| 丝袜av一区| 欧美激情 亚洲a∨综合| 亚洲一区二区毛片| 国产精品99免费看| 91一区二区| 日本一区免费网站| 亚洲天堂一区二区| 国产精品成人**免费视频| 夜夜嗨网站十八久久 | 欧美激情精品| 欧美日韩一区二区三区在线电影| 久久亚洲精品中文字幕蜜潮电影| 久久av电影| 国产激情欧美|