乾飯人乾飯魂,年輕人乾了這碗多線程,就是人上人!

開篇閒扯

一年又一年,年年多線程。不論你是什麼程序員,都逃脫不了多線程併發的魔爪。因爲它從盤古開天闢地的時候就有了,就是在計算機中對現實世界的一種抽象。因此,放輕鬆別害怕,肝了這系列的多線程文章,差不多能吊打面試官了(可別真動手...)。

併發症

併發問題,曾經在單核單線程的機器上是不存在的(不是不想,是做不到)。假如把計算機看成一個木桶,那麼跟我們Java開發人員關係最大的就是CPU、內存、IO設備。這三塊木板發展至今,彼此之間也形成了較大的性能差異。CPU的核心數線程數在不斷增多,內存的速度卻跟不上CPU的步伐,同理IO設備也沒能跟上內存的步伐。於是就加緩存,經過科學論證三級緩存最靠譜,於是就有了常見的CPU三級緩存。然後前輩們再對操作系統做各類調度層面的深度優化,通過軟硬兼施的手法,使得軟件與硬件的完美結合,纔有如今繁榮的互聯網。而我們不過是在這座城市裏的打工人罷了。 言歸正傳,本文將分別說明在併發世界裏的“三宗罪”:可見性、原子性、有序性。

罪狀一:可見性

前文中有說到CPU的發展經歷了從單核單線程到現在的多核心多線程,而內存的讀寫性能卻供應不上CPU的處理能力,於是就增加了緩存,至於前文中提到的三級緩存爲什麼是三級,不在本文討論範圍,有興趣自己看去。。。

爲什麼會有可見性問題?

在單核心時代,所有的線程都是交給一個CPU串行執行,因此不論有多少線程都是排隊執行,也就不會形成線程A與B同時競爭target變量的競爭狀態,如圖一。

來到多核心多線程時代,每顆CPU都有各自的緩存,如果多個線程分別在不同的CPU上運行,且需要同時操作同一個數據。而每顆CPU在處理內存中的數據時,會先將目標數據緩存到CPU緩存中。這時候CPU們各幹各的,也不管目標值有沒有被其他CPU修改過,自己在緩存中修改後不管三七二十一就寫回去,這肯定是不行的啊兄弟...,而這就是我們Java中常說的數據可見性問題,再追根溯源就是:CPU級別的緩存一致性協議。後邊文章會詳細解釋(別問具體時間,問了就是明天)。

可見性問題怎麼解決?

這個簡單,如果僅僅是解決可見性,那就Volatile關鍵字用起來(也不是萬能的,慎重考慮),它會將共享變量數據從線程工作內存刷新到主存中,而這個關鍵字的實現基礎是Java規範的內存模型,注意,這裏要和JVM內存模型區分開,兩者是不一樣的東西。那麼Java內存模型又是什麼樣的,爲啥設計這個內存模型,有哪些好處?下篇詳細解釋!本文就先放一張簡單的圖:

罪狀二:原子性

大家都知道CPU的運行時間是分片進行的,可能CPU這段時間在執行我寫的if-else,下一時刻由於操作系統的調度當前線程丟失時間片,又執行其他線程任務去了(呸!渣男)。打斷了我當前線程的一個或者多個操作流程,這就是原子性被破壞了,也就是多線程無鎖情況下的ABA問題。跟我們期望的完全不一樣啊,還是看圖說話:

解釋一下就是:想要得到temp爲2的結果,但是隻能得到1,原因就是運行A線程的CPU幹別的去了,而這時候B線程所在的CPU後發制A,搶先完成了++的操作並寫回內存,但是A不知道,還傻傻的以爲它的到的是temp的初戀,又傻傻的寫會去,然後就心態崩了呀!偷襲~(出錯)

罪狀三:有序性

如果說原子性問題是硬件工程師挖的坑(CPU別切換多好),那有序性就妥妥的是軟件工程師下了老鼠夾子(誇張了啊,其實都是爲了效率)。之所以存在有序性問題,完全是編譯大神們對我們的關愛,知道我們普通Coder對性能的要求是能跑就行。

因此,在Java代碼在編譯時期動了手腳,比如說:鎖消除、鎖粗化(需要進行逃逸性分析等技術手段)或者是將A、B兩段操作互換順序。但是,所有的這一切都不能影響源碼在單線程執行情況下的最終結果,即as-if-serial語義。這是個很頂層的協議,不論是編譯器、運行時狀態還是處理器都必須遵守該語義。這是保證程序正確性的大前提。當然,編譯器不僅僅要準守as-if-serial語義,還要準守以下八大規則--Happens-Before規則(八仙過海各顯神通):

什麼是Happens-Before規則?

一段程序中,前面運行後的結果,對後面的操作來說均可見。即:不論怎麼編譯優化(編譯優化的文章以後會寫,關注我,全免費)都不能違背這一指導思想。不能忘本

注:文章裏所有類似“先於”、“早於”等詞並不嚴謹不能和Happens-Before劃等號,只是這樣說更好理解,較爲準確的含義是:操作結果對後者可見。

其實,總結來說就是JMM、編譯器和程序員之間的關係。


JMM對程序員說:你按順序寫,執行結果就是按照你寫的順序執行的,有BUG就是你自己的問題。
程序員:好的,聽你的!
JMM對編譯器說:你不能隨便改變程序員的代碼順序,我都跟他承諾寫啥是啥了,別搞錯了。
編譯器:收到!(可我還是想優化,我不影響你不就行了,這優化我做定了,奧利給!)

於是就有了這些規則,而對於我們CRUD Boy來說都是不可見的,瞭解一下就OK!

感謝各位看官!

作者:羅拉快跑跑跑跑
原文鏈接:https://www.cnblogs.com/RollerRunning/p/14047049

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