併發編程的嘗試之volatile的困惑

去年在使用C++實現一個線程安全的HashMap時,當我實現了HashMap,準備引入鎖時,面對這麼多共享的變量,我竟一時不知那些變量該使用volatile去聲明,volatile一個在我大學畢業前就自認爲搞的爛透的一個概念,當有人問我volatile時,我會從GCC編譯器是如何實現volatile的,再到CMP,SMP,架構下CPU是如實現數據的可見性,及緩存一致性協議,內存欄柵。但在二年後的去年六七月份,當我真正想實現一個在多線程併發環境中使用的HashMap時,我卻不知道該如何去使用它

有道是 紙上得來終覺淺,決知此事需躬行,不躬不知道,一躬嚇一跳,原來我真的是隻會與別人誇誇其談,紙上談兵的一個渣渣,一個垃圾,只會吹吹牛逼罷了

 

當時的我感覺併發編程實在是太難了,太難了,像我這種渣渣還是老老實實寫寫業務BUG,改改配置吧!我的自信心也因此倍受打擊,因此併發編程大業無疾而終,唯留那殘缺的代碼獨自躺在烏班圖的虛擬機中

 

最近在瞭解到Java的volatile實現時,我腦子裏,第一個蹦出來的疑問就是爲什麼JMM只要保證在JVM中各個Java字節碼解釋器線程棧中的副本變量(工作內存)與,主內存中的變量同步,就可以保證,共享變量的可見性,而完全不用關心每顆物理CPU核心的寄存器,一級cache,二級cache,共享的三級cache中的值有沒有回寫到內存中?JVM完全無視了硬件層次的數據一致性,而C/C++中的volatile保證的是一個變量在從內存通過3,2,1級cache到達cpu寄存器進行運算後要馬上回寫到內存,下次運算時再從內存中獲取,這期間會被cacheline cache住,由membar及緩存一致性協議來保證cacheline中的數據對其它核心及其它cpu的可見性

 

我反編譯了一段使用volatile修飾的int類型的Java代碼,把反編譯的字節碼指令,對着JVM解釋器源碼,一個一個的查看JVM是怎樣用C++中的volatile實現Java中使用volatile修飾的變量的,我試圖在JVM解釋器的C++源碼中找到與volatile的相關的蛛絲馬跡,但未果。於是我合上筆記本,怏怏地躺在牀上打開小吊扇,對着旋轉的小吊扇,我說吊扇啊,吊扇,請你告訴我?This is why

 

吊扇拖夢與我,如此,如此,這般,這般,一覺醒來,我頓悟,原來如此,,,

 

我稱我的頓悟爲變量對編譯器的可見性或編譯器對變量的可感知性,Java代碼中的變量只能被Javac編譯器感知到,JVM虛擬了一個的基於棧的CPU,每一個JVM解釋器線程就是一顆虛擬CPU,在JVM中只需要保證volatile修飾的變量被加載到這個棧中進行運算後立刻馬上同步到主內存中(同時還起membar的做用)即可保證對同一個JVM進程中各個字節碼解釋器線程的可見性,Java代碼被編譯成字節碼後就是一堆相對偏移量和字節碼,在被解釋器,翻譯成物理CPU的指令後就是另一堆相對偏移量和指令而已,Java代碼是用Javac編譯器編譯的,JVM解釋器是用C++實現的由g++編譯器編譯,Java代碼中的一個變量是不可能被g++編譯器感知到,從而把Java中的一個變量優化到物理CPU的寄存器中

我試着講清楚但可能還是有點不清楚,因爲我自己都不確定這是一個正確的說法

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章