电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

Java并發編程-volatile

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

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

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

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

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

Java并發編程-volatile

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

Java并發編程-volatile

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

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

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

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

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

2、 Java 內存模型

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

Java內存模型的主要目標是定義程序中各個變量的訪問規則,即變量在內存中的存儲和從內存中取出變量這樣的底層細節。其規定了所有變量都存儲在主內存,每個線程還有自己的工作內存,線程讀寫變量時需先復制到工作內存,執行完計算操作后再回寫到主內存,每個線程還不能訪問其他線程的工作內存。大致示意圖如下:

Java并發編程-volatile

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

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

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

3 、volatile 背后實現

那么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(); }}

先看看字節碼層面,JVM都做了什么。

Java并發編程-volatile

圖四

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

Java并發編程-volatile

圖五

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

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

再搜索關鍵字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(); }

在這段代碼中,會先判斷tos_type,后面分別有不同的基礎類型的實現,比如int就調用release_int_field_put,byte就調用release_byte_field_put等等。以int類型為例,繼續搜索方法release_int_field_put,在oop.hpp可以看到如下代碼:

void release_int_field_put(int offset, jint contents);

這段代碼實際是內聯oop.inline.hpp,具體的實現是這樣的:

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

其實看到這,可以看到上一篇文章很熟悉的oop.hpp和oop.inline.hpp,就是很熟悉的Java對象模型。繼續看OrderAccess::release_store,可以在orderAccess.hpp找到對應的實現方法:

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

實際上這個方法的實現又有很多內聯的針對不同的CPU有不同的實現的,在src/os_cpu目錄下可以看到不同的實現,以orderAccess_linux_x86.inline.hpp為例,是這么實現的:

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

可以看到其實Java的volatile操作,在JVM實現層面第一步是給予了C++的原語實現,接下來呢再看bytecodeInterpreter.cpp截取的代碼,會再給予一個OrderAccess::storeload()操作,而這個操作執行的代碼是這樣的(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來看到的背后實現:lock; addl,其實這個就是內存屏障,關于內存屏障的詳細說明可以看下orderAccess.hpp的注釋。內存屏障提供了3個功能:確保指令重排序時不會把其后面的指令排到內存屏障之前的位置,也不會把前面的指令排到內存屏障的后面;強制將對緩存的修改操作立即寫入主存;如果是寫操作,它會導致其他CPU中對應的緩存行無效。這3個功能又是怎么做到的呢?來看下內存屏障的策略:

在每個volatile寫操作前面插入storestore屏障;

在每個volatile寫操作后面插入storeload屏障;

在每個volatile讀操作后面插入loadload屏障;

在每個volatile讀操作后面插入loadstore屏障;

其中loadload和loadstore對應的是方法acquire,storestore對應的是方法release,storeload對應的是方法fence。

4 、volatile 應用場景

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; }}

為什么要這樣寫,這個網上有很多資料,這里就不贅述了。

4.2 java.util.concurrent

大量的應用在j.u.c下的各個基礎類和工具欄,構成Java并發包的基礎。后續并發編程的學習就可以按照這個路線圖來學習了。

Java并發編程-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

標簽: Java
相關文章:
主站蜘蛛池模板: 智慧食堂_食堂管理系统_食堂订餐_食堂消费系统—客易捷 | 润滑脂-高温润滑脂-轴承润滑脂-食品级润滑油-索科润滑油脂厂家 | LED显示屏_LED屏方案设计精准报价专业安装丨四川诺显科技 | 航空障碍灯_高中低光强航空障碍灯_民航许可认证航空警示灯厂家-东莞市天翔航天科技有限公司 | 气动隔膜阀_气动隔膜阀厂家_卫生级隔膜阀价格_浙江浙控阀门有限公司 | 南京蜂窝纸箱_南京木托盘_南京纸托盘-南京博恒包装有限公司 | 专注提供国外机电设备及配件-工业控制领域一站式服务商-深圳市华联欧国际贸易有限公司 | 隧道烘箱_隧道烘箱生产厂家-上海冠顶专业生产烘道设备 | 电动手术床,医用护理床,led手术无影灯-曲阜明辉医疗设备有限公司 | 交通气象站_能见度检测仪_路面状况监测站- 天合环境科技 | 磁力轮,磁力联轴器,磁齿轮,钕铁硼磁铁-北京磁运达厂家 | 悬浮拼装地板_篮球场木地板翻新_运动木地板价格-上海越禾运动地板厂家 | 上海刑事律师|刑事辩护律师|专业刑事犯罪辩护律师免费咨询-[尤辰荣]金牌上海刑事律师团队 | 软文世界-软文推广-软文营销-新闻稿发布-一站式软文自助发稿平台 | 长沙中央空调维修,中央空调清洗维保,空气能热水工程,价格,公司就找维小保-湖南维小保环保科技有限公司 | 钢绞线万能材料试验机-全自动恒应力两用机-混凝土恒应力压力试验机-北京科达京威科技发展有限公司 | 电磁铁_小型推拉电磁铁_电磁阀厂家-深圳市宗泰电机有限公司 | 温湿度记录纸_圆盘_横河记录纸|霍尼韦尔记录仪-广州汤米斯机电设备有限公司 | 智能垃圾箱|垃圾房|垃圾分类亭|垃圾分类箱专业生产厂家定做-宿迁市传宇环保设备有限公司 | 亚克力制品定制,上海嘉定有机玻璃加工制作生产厂家—官网 | 长江船运_国内海运_内贸船运_大件海运|运输_船舶运输价格_钢材船运_内河运输_风电甲板船_游艇运输_航运货代电话_上海交航船运 | 自动售货机_无人售货机_专业的自动售货机运营商_免费投放售货机-广州富宏主官网 | 高柔性拖链电缆-聚氨酯卷筒电缆-柔性屏蔽电缆厂家-玖泰电缆 | 废气处理设备-工业除尘器-RTO-RCO-蓄热式焚烧炉厂家-江苏天达环保设备有限公司 | 车充外壳,车载充电器外壳,车载点烟器外壳,点烟器连接头,旅行充充电器外壳,手机充电器外壳,深圳市华科达塑胶五金有限公司 | 台式低速离心机-脱泡离心机-菌种摇床-常州市万丰仪器制造有限公司 | 电子元器件呆滞料_元器件临期库存清仓尾料_尾料优选现货采购处理交易商城 | 船用烟火信号弹-CCS防汛救生圈-船用救生抛绳器(海威救生设备) | 航空障碍灯_高中低光强航空障碍灯_民航许可认证航空警示灯厂家-东莞市天翔航天科技有限公司 | 医用空气消毒机-医用管路消毒机-工作服消毒柜-成都三康王 | PCB接线端子_栅板式端子_线路板连接器_端子排生产厂家-置恒电气 喷码机,激光喷码打码机,鸡蛋打码机,手持打码机,自动喷码机,一物一码防伪溯源-恒欣瑞达有限公司 假肢-假肢价格-假肢厂家-河南假肢-郑州市力康假肢矫形器有限公司 | 深圳彩钢板_彩钢瓦_岩棉板_夹芯板_防火复合彩钢板_长鑫 | 上海租奔驰_上海租商务车_上海租车网-矢昂汽车服务公司 | 桌上式超净工作台-水平送风超净工作台-上海康路仪器设备有限公司 | 超声波成孔成槽质量检测仪-压浆机-桥梁预应力智能张拉设备-上海硕冠检测设备有限公司 | 股指期货-期货开户-交易手续费佣金加1分-保证金低-期货公司排名靠前-万利信息开户 | 矿用履带式平板车|探水钻机|气动架柱式钻机|架柱式液压回转钻机|履带式钻机-启睿探水钻机厂家 | 网站优化公司_SEO优化_北京关键词百度快速排名-智恒博网络 | 亿诺千企网-企业核心产品贸易| 食品机械专用传感器-落料放大器-低价接近开关-菲德自控技术(天津)有限公司 | 衬氟止回阀_衬氟闸阀_衬氟三通球阀_衬四氟阀门_衬氟阀门厂-浙江利尔多阀门有限公司 |