Java多線程之有序性(一)

學(xué)識甚淺盟迟,大家僅作參考吧。
對于初學(xué)者來書潦闲,這一章涉及到的知識點(diǎn)很多攒菠,在這之前,我總結(jié)幾點(diǎn)重要的知識點(diǎn):
1.Java內(nèi)存模型歉闰。為什么內(nèi)存模型這么重要辖众?其實(shí)細(xì)想一下,多線程和單線程相比和敬,出現(xiàn)問題不就是內(nèi)存里面的值可能與預(yù)期值(單線程運(yùn)行/串行運(yùn)行)之間不一致嘛凹炸。所以一定至少要知道讀寫操作是怎么操作內(nèi)存的!昼弟!
2.Java程序的運(yùn)行順序啤它。程序是如何按照happen-before原則運(yùn)行的。
3.Java重排序
4.本章內(nèi)容做一個假設(shè)变骡,即每個線程運(yùn)行在自己的處理器上救欧,不考慮基于時(shí)間片分時(shí)實(shí)現(xiàn)的多線程,即我們這章討論的多線程是指不同的處理器上的線程锣光。(因?yàn)榛跁r(shí)間片分時(shí)的多線程也就是單一處理器的多線程在有序性上討論起來很麻煩,大家可以參考Java多線程編程指南铝耻,也可以留言)

前兩點(diǎn)基礎(chǔ)大家上網(wǎng)查查誊爹,我主要講一下導(dǎo)致并發(fā)問題的第三點(diǎn)。先明白幾個概念:
源代碼順序:源代碼中所指定的內(nèi)存訪問操作順序瓢捉。
程序順序:我們可以理解為編譯得到機(jī)器碼或者解釋執(zhí)行的字節(jié)碼(之后把兩者統(tǒng)稱為字節(jié)碼)所指定的內(nèi)存訪問順序频丘。
執(zhí)行順序:內(nèi)存訪問在指定處理器上的實(shí)際執(zhí)行順序。
感知順序:給定處理器感知到其他處理器內(nèi)存訪問的順序泡态。

有點(diǎn)難度的東西來了搂漠,看不下去就一點(diǎn)一點(diǎn)看吧=o=
在此基礎(chǔ)上我們將重排序分為兩部分:指令重排序存儲子系統(tǒng)重排序
指令重排序:表現(xiàn)在 程序順序與源代碼順序不一致 或者 執(zhí)行順序與程序順序 不一致某弦。
解釋一下就是:源代碼中指定的內(nèi)存訪問順序與得到的字節(jié)碼順序不一樣 或者 字節(jié)碼順序與實(shí)際的執(zhí)行順序不一樣桐汤。
既然產(chǎn)生了不一樣,那么問題肯定是出在連接這三個過程的中間件上面靶壮。學(xué)過java的同學(xué)應(yīng)該知道怔毛,java平臺包括兩種編譯器:
靜態(tài)編譯器(javac)和動態(tài)編譯器(jit:just in time)。靜態(tài)編譯器是將.java文件編譯成.class文件(二進(jìn)制文件)腾降,之后便可以解釋執(zhí)行拣度。動態(tài)編譯器是將.class文件編譯成機(jī)器碼,之后再由jvm運(yùn)行螃壤。jit主要是做性能上面的優(yōu)化抗果,如熱點(diǎn)代碼編譯成本地代碼,加速調(diào)用奸晴。(說點(diǎn)題外話冤馏,這些東西本來應(yīng)該在課上就應(yīng)該學(xué)到的,但是......誒)好的寄啼,那么指令重排序的根源主要在哪呢宿接?
其實(shí)javac基本不會調(diào)整指令順序,調(diào)整指令順序的大多出在jit優(yōu)化上辕录。
有沒有人想問睦霎,既然jit優(yōu)化會出問題,那么為什么還要這個優(yōu)化白叩8迸!(我覺得能問出問題起碼跟上了)
在單線程情況下蚣旱,我們并不在乎具體的內(nèi)存訪問順序是什么樣的碑幅,只要展示出來的結(jié)果是按照我的源代碼順序執(zhí)行的就好了戴陡,我不會管你究竟在我的字節(jié)碼或者機(jī)器碼中調(diào)整了怎樣的順序。 也就是說沟涨,編譯器的優(yōu)化它并不會造成結(jié)果的偏差恤批,但是帶來的性能的提升確實(shí)巨大的,就好像你的mysql用了索引和沒用索引一樣裹赴,代碼量上去之后喜庞,優(yōu)化就是必須的。
所以棋返,問題就出在了并發(fā)訪問時(shí)延都,你一旦調(diào)整了指令順序,而且又在沒有同步的情況下睛竣,那么我的一個線程就很可能讀到另一個線程操作的中間過程晰房。給大家舉個例子(第一章提到的初始化問題):
Person p = new Person();那么我們的Jit編譯器會怎樣操作呢?會分為以下三個子操作射沟,
①.分配Person實(shí)例所需要的內(nèi)存空間;
objRef = allocate(Person.class);(推薦大家看一下Java反射機(jī)制殊者,很重要的很基礎(chǔ)的很...有用的=@=)
②.調(diào)用Person的構(gòu)造方法初始化objRef引用指向一個Person實(shí)例;
invokeConstructor(objRef);
③.將Person實(shí)例引用objRef賦值給實(shí)例變量p;
p = objRef;
在優(yōu)化的時(shí)候验夯,我們很可能將操作③調(diào)整到操作②之前進(jìn)行幽污,也就是先將一個空的實(shí)例賦給p。那么多線程訪問的時(shí)候簿姨,其它線程很可能用這個空的實(shí)例距误,從而造成錯誤。

存儲子系統(tǒng)重排序:表現(xiàn)在感知順序與執(zhí)行順序不一樣扁位。
首先我們要明確一下什么是存儲子系統(tǒng):簡單理解就是主存與寄存器之間的高速緩存准潭,細(xì)一點(diǎn)的話可以加上寫緩沖器(提高寫主存的效率)。
假設(shè)我們兩個內(nèi)存訪問操作都是嚴(yán)格按照程序順序執(zhí)行的域仇,即不發(fā)生指令重排的情況刑然,在存儲子系統(tǒng)的作用下也會造成其他處理器(線程) 感知到 這兩個內(nèi)存訪問操作的順序不一樣。那么暇务,這兩個操作可以有四種:其實(shí)就是讀操作和寫操作的排列組合泼掠。
以讀寫操作為例:在重排序的作用下,會讓其他線程感覺讀操作被排到了寫操作之后垦细。
但是可能還是不太清楚择镇,考慮兩個線程P1和P2,它們有兩個共享變量data(int)和ready(boolean)括改,P1的任務(wù)是更新data并將ready變?yōu)閠rue腻豌,P2的任務(wù)是不斷輪詢r(jià)eady的值,當(dāng)ready為true時(shí)打印出data的值。現(xiàn)在P1更新了data吝梅,并將ready置為true虱疏,并在無指令重排的情況下把值都放到寫緩沖區(qū)。但是苏携,寫緩沖區(qū)并不保證操作的先入先出原則做瞪,即可能先把ready的值更新回高速緩存(或主存),然后再把data值寫回右冻。那么在兩個操作之間装蓬,P2可能看見了ready為true,而此時(shí)data的新值還在寫緩存中国旷,并未更新回去,就造成了錯誤茫死。

東西其實(shí)還蠻多的跪但,大家細(xì)細(xì)體會,下一章我們再具體討論有序性峦萎。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末屡久,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子爱榔,更是在濱河造成了極大的恐慌被环,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件详幽,死亡現(xiàn)場離奇詭異筛欢,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)唇聘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進(jìn)店門版姑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人迟郎,你說我怎么就攤上這事剥险。” “怎么了宪肖?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵表制,是天一觀的道長。 經(jīng)常有香客問我控乾,道長么介,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任蜕衡,我火速辦了婚禮夭拌,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己鸽扁,他們只是感情好蒜绽,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著桶现,像睡著了一般躲雅。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上骡和,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天相赁,我揣著相機(jī)與錄音,去河邊找鬼慰于。 笑死钮科,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的婆赠。 我是一名探鬼主播绵脯,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼休里!你這毒婦竟也來了蛆挫?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤妙黍,失蹤者是張志新(化名)和其女友劉穎悴侵,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拭嫁,經(jīng)...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡可免,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了做粤。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片巴元。...
    茶點(diǎn)故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖驮宴,靈堂內(nèi)的尸體忽然破棺而出逮刨,到底是詐尸還是另有隱情,我是刑警寧澤堵泽,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布修己,位于F島的核電站,受9級特大地震影響迎罗,放射性物質(zhì)發(fā)生泄漏睬愤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一纹安、第九天 我趴在偏房一處隱蔽的房頂上張望尤辱。 院中可真熱鬧砂豌,春花似錦、人聲如沸光督。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽结借。三九已至筐摘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間船老,已是汗流浹背咖熟。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留柳畔,地道東北人馍管。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像薪韩,于是被迫代替她去往敵國和親确沸。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評論 2 355

推薦閱讀更多精彩內(nèi)容