Java并發(fā)專(zhuān)題【3】Java內(nèi)存模型以及happens-before規(guī)則

JMM的介紹

在上一篇文章中總結(jié)了線程的狀態(tài)轉(zhuǎn)換和一些基本操作,對(duì)多線程已經(jīng)有一點(diǎn)基本的認(rèn)識(shí)了沈自,如果多線程編程只有這么簡(jiǎn)單毡代,那我們就不必費(fèi)勁周折的去學(xué)習(xí)它了。

在多線程中稍微不注意就會(huì)出現(xiàn)線程安全問(wèn)題间校,那么什么是線程安全問(wèn)題矾克?我的認(rèn)識(shí)是,在多線程下代碼執(zhí)行的結(jié)果與預(yù)期正確的結(jié)果不一致憔足,該代碼就是線程不安全的胁附,否則則是線程安全的。雖然這種回答似乎不能獲取什么內(nèi)容滓彰,可以google下控妻。在<<深入理解Java虛擬機(jī)>>中看到的定義。

原文如下:

當(dāng)多個(gè)線程訪問(wèn)同一個(gè)對(duì)象時(shí)揭绑,如果不用考慮這些線程在運(yùn)行時(shí)環(huán)境下的調(diào)度和交替運(yùn)行弓候,也不需要進(jìn)行額外的同步,或者在調(diào)用方進(jìn)行任何其他的協(xié)調(diào)操作洗做,調(diào)用這個(gè)對(duì)象的行為都可以獲取正確的結(jié)果弓叛,那這個(gè)對(duì)象是線程安全的。

關(guān)于定義的理解這是一個(gè)仁者見(jiàn)仁智者見(jiàn)智的事情诚纸。

出現(xiàn)線程安全的問(wèn)題一般是因?yàn)橹鲀?nèi)存和工作內(nèi)存數(shù)據(jù)不一致性和重排序?qū)е碌淖辏鉀Q線程安全的問(wèn)題最重要的就是理解這兩種問(wèn)題是怎么來(lái)的,那么畦徘,理解它們的核心在于理解java內(nèi)存模型(JMM)毕籽。

在多線程條件下,多個(gè)線程肯定會(huì)相互協(xié)作完成一件事情井辆,一般來(lái)說(shuō)就會(huì)涉及到多個(gè)線程間相互通信告知彼此的狀態(tài)以及當(dāng)前的執(zhí)行結(jié)果等关筒,另外,為了性能優(yōu)化杯缺,還會(huì)涉及到編譯器指令重排序和處理器指令重排序蒸播。下面會(huì)一一來(lái)聊聊這些知識(shí)。

內(nèi)存模型抽象結(jié)構(gòu)

線程間協(xié)作通信可以類(lèi)比人與人之間的協(xié)作的方式,在現(xiàn)實(shí)生活中袍榆,之前網(wǎng)上有個(gè)流行語(yǔ)“你媽喊你回家吃飯了”胀屿,就以這個(gè)生活場(chǎng)景為例。小明在外面玩耍包雀,小明媽媽在家里做飯宿崭,做晚飯后準(zhǔn)備叫小明回家吃飯,那么就存在兩種方式:

小明媽媽要去上班了十分緊急這個(gè)時(shí)候手機(jī)又沒(méi)有電了才写,于是就在桌子上貼了一張紙條“飯做好了葡兑,放在...”小明回家后看到紙條如愿吃到媽媽做的飯菜,那么赞草,如果將小明媽媽和小明作為兩個(gè)線程讹堤,那么這張紙條就是這兩個(gè)線程間通信的共享變量,通過(guò)讀寫(xiě)共享變量實(shí)現(xiàn)兩個(gè)線程間協(xié)作房资;

還有一種方式就是蜕劝,媽媽的手機(jī)還有電,媽媽在趕去坐公交的路上給小明打了個(gè)電話轰异,這種方式就是通知機(jī)制來(lái)完成協(xié)作岖沛。同樣,可以引申到線程間通信機(jī)制搭独。

通過(guò)上面這個(gè)例子婴削,應(yīng)該有些認(rèn)識(shí)。在并發(fā)編程中主要需要解決兩個(gè)問(wèn)題:1. 線程之間如何通信牙肝;2.線程之間如何完成同步(這里的線程指的是并發(fā)執(zhí)行的活動(dòng)實(shí)體)唉俗。通信是指線程之間以何種機(jī)制來(lái)交換信息,主要有兩種:共享內(nèi)存和消息傳遞配椭。

這里虫溜,可以分別類(lèi)比上面的兩個(gè)舉例。java內(nèi)存模型是共享內(nèi)存的并發(fā)模型股缸,線程之間主要通過(guò)讀-寫(xiě)共享變量來(lái)完成隱式通信衡楞。如果程序員不能理解Java的共享內(nèi)存模型在編寫(xiě)并發(fā)程序時(shí)一定會(huì)遇到各種各樣關(guān)于內(nèi)存可見(jiàn)性的問(wèn)題。

1.哪些是共享變量

在java程序中所有實(shí)例域敦姻,靜態(tài)域和數(shù)組元素都是放在堆內(nèi)存中(所有線程均可訪問(wèn)到瘾境,是可以共享的),而局部變量镰惦,方法定義參數(shù)和異常處理器參數(shù)不會(huì)在線程間共享迷守。共享數(shù)據(jù)會(huì)出現(xiàn)線程安全的問(wèn)題,而非共享數(shù)據(jù)不會(huì)出現(xiàn)線程安全的問(wèn)題旺入。關(guān)于JVM運(yùn)行時(shí)內(nèi)存區(qū)域在后面的文章會(huì)講到兑凿。

2.JMM抽象結(jié)構(gòu)模型

我們知道CPU的處理速度和主存的讀寫(xiě)速度不是一個(gè)量級(jí)的凯力,為了平衡這種巨大的差距,每個(gè)CPU都會(huì)有緩存礼华。因此沮协,共享變量會(huì)先放在主存中,每個(gè)線程都有屬于自己的工作內(nèi)存卓嫂,并且會(huì)把位于主存中的共享變量拷貝到自己的工作內(nèi)存,之后的讀寫(xiě)操作均使用位于工作內(nèi)存的變量副本聘殖,并在某個(gè)時(shí)刻將工作內(nèi)存的變量副本寫(xiě)回到主存中去晨雳。JMM就從抽象層次定義了這種方式,并且JMM決定了一個(gè)線程對(duì)共享變量的寫(xiě)入何時(shí)對(duì)其他線程是可見(jiàn)的奸腺。

如圖為JMM抽象示意圖餐禁,線程A和線程B之間要完成通信的話,要經(jīng)歷如下兩步:

線程A從主內(nèi)存中將共享變量讀入線程A的工作內(nèi)存后并進(jìn)行操作突照,之后將數(shù)據(jù)重新寫(xiě)回到主內(nèi)存中帮非;

線程B從主存中讀取最新的共享變量

從橫向去看看,線程A和線程B就好像通過(guò)共享變量在進(jìn)行隱式通信讹蘑。這其中有很有意思的問(wèn)題末盔,如果線程A更新后數(shù)據(jù)并沒(méi)有及時(shí)寫(xiě)回到主存,而此時(shí)線程B讀到的是過(guò)期的數(shù)據(jù)座慰,這就出現(xiàn)了“臟讀”現(xiàn)象陨舱。

可以通過(guò)同步機(jī)制(控制不同線程間操作發(fā)生的相對(duì)順序)來(lái)解決或者通過(guò)volatile關(guān)鍵字使得每次volatile變量都能夠強(qiáng)制刷新到主存,從而對(duì)每個(gè)線程都是可見(jiàn)的版仔。

3. 重排序

一個(gè)好的內(nèi)存模型實(shí)際上會(huì)放松對(duì)處理器和編譯器規(guī)則的束縛游盲,也就是說(shuō)軟件技術(shù)和硬件技術(shù)都為同一個(gè)目標(biāo)而進(jìn)行奮斗:在不改變程序執(zhí)行結(jié)果的前提下,盡可能提高并行度蛮粮。JMM對(duì)底層盡量減少約束益缎,使其能夠發(fā)揮自身優(yōu)勢(shì)。因此然想,在執(zhí)行程序時(shí)莺奔,為了提高性能,編譯器和處理器常常會(huì)對(duì)指令進(jìn)行重排序又沾。一般重排序可以分為如下三種:

編譯器優(yōu)化的重排序弊仪。編譯器在不改變單線程程序語(yǔ)義的前提下,可以重新安排語(yǔ)句的執(zhí)行順序杖刷;

指令級(jí)并行的重排序±現(xiàn)代處理器采用了指令級(jí)并行技術(shù)來(lái)將多條指令重疊執(zhí)行。如果不存在數(shù)據(jù)依賴(lài)性滑燃,處理器可以改變語(yǔ)句對(duì)應(yīng)機(jī)器指令的執(zhí)行順序役听;

內(nèi)存系統(tǒng)的重排序。由于處理器使用緩存和讀/寫(xiě)緩沖區(qū),這使得加載和存儲(chǔ)操作看上去可能是在亂序執(zhí)行的典予。

如圖甜滨,1屬于編譯器重排序,而2和3統(tǒng)稱(chēng)為處理器重排序瘤袖。這些重排序會(huì)導(dǎo)致線程安全的問(wèn)題衣摩,一個(gè)很經(jīng)典的例子就是DCL問(wèn)題,這個(gè)在以后的文章中會(huì)具體去聊捂敌。針對(duì)編譯器重排序艾扮,JMM的編譯器重排序規(guī)則會(huì)禁止一些特定類(lèi)型的編譯器重排序;針對(duì)處理器重排序占婉,編譯器在生成指令序列的時(shí)候會(huì)通過(guò)插入內(nèi)存屏障指令來(lái)禁止某些特殊的處理器重排序泡嘴。

那么什么情況下,不能進(jìn)行重排序了逆济?下面就來(lái)說(shuō)說(shuō)數(shù)據(jù)依賴(lài)性酌予。有如下代碼:

double?pi =?3.14?//A

double?r =?1.0?//B

double?area = pi * r * r?//C

這是一個(gè)計(jì)算圓面積的代碼,由于A,B之間沒(méi)有任何關(guān)系奖慌,對(duì)最終結(jié)果也不會(huì)存在關(guān)系抛虫,它們之間執(zhí)行順序可以重排序。因此可以執(zhí)行順序可以是A->B->C或者B->A->C執(zhí)行最終結(jié)果都是3.14简僧,即A和B之間沒(méi)有數(shù)據(jù)依賴(lài)性莱褒。

具體的定義為:如果兩個(gè)操作訪問(wèn)同一個(gè)變量,且這兩個(gè)操作有一個(gè)為寫(xiě)操作涎劈,此時(shí)這兩個(gè)操作就存在數(shù)據(jù)依賴(lài)性這里就存在三種情況:1. 讀后寫(xiě)广凸;2.寫(xiě)后寫(xiě);3. 寫(xiě)后讀蛛枚,者三種操作都是存在數(shù)據(jù)依賴(lài)性的谅海,如果重排序會(huì)對(duì)最終執(zhí)行結(jié)果會(huì)存在影響。

編譯器和處理器在重排序時(shí)蹦浦,會(huì)遵守?cái)?shù)據(jù)依賴(lài)性扭吁,編譯器和處理器不會(huì)改變存在數(shù)據(jù)依賴(lài)性關(guān)系的兩個(gè)操作的執(zhí)行順序。

另外盲镶,還有一個(gè)比較有意思的就是as-if-serial語(yǔ)義侥袜。

as-if-serial

as-if-serial語(yǔ)義的意思是:不管怎么重排序(編譯器和處理器為了提供并行度),(單線程)程序的執(zhí)行結(jié)果不能被改變溉贿。編譯器枫吧,runtime和處理器都必須遵守as-if-serial語(yǔ)義。

as-if-serial語(yǔ)義把單線程程序保護(hù)了起來(lái)宇色,遵守as-if-serial語(yǔ)義的編譯器九杂,runtime和處理器共同為編寫(xiě)單線程程序的程序員創(chuàng)建了一個(gè)幻覺(jué):?jiǎn)尉€程程序是按程序的順序來(lái)執(zhí)行的颁湖。

比如上面計(jì)算圓面積的代碼,在單線程中例隆,會(huì)讓人感覺(jué)代碼是一行一行順序執(zhí)行上甥捺,實(shí)際上A,B兩行不存在數(shù)據(jù)依賴(lài)性可能會(huì)進(jìn)行重排序,即A镀层,B不是順序執(zhí)行的镰禾。as-if-serial語(yǔ)義使程序員不必?fù)?dān)心單線程中重排序的問(wèn)題干擾他們,也無(wú)需擔(dān)心內(nèi)存可見(jiàn)性問(wèn)題唱逢。

4. happens-before規(guī)則

上面的內(nèi)容講述了重排序原則羡微,一會(huì)是編譯器重排序一會(huì)是處理器重排序,如果讓程序員再去了解這些底層的實(shí)現(xiàn)以及具體規(guī)則惶我,那么程序員的負(fù)擔(dān)就太重了,嚴(yán)重影響了并發(fā)編程的效率博投。

因此绸贡,JMM為程序員在上層提供了六條規(guī)則,這樣我們就可以根據(jù)規(guī)則去推論跨線程的內(nèi)存可見(jiàn)性問(wèn)題毅哗,而不用再去理解底層重排序的規(guī)則听怕。下面以?xún)蓚€(gè)方面來(lái)說(shuō)。

4.1 happens-before定義

happens-before的概念最初由Leslie Lamport在其一篇影響深遠(yuǎn)的論文(《Time虑绵,Clocks and the Ordering of Events in a Distributed System》)中提出尿瞭,有興趣的可以google一下。JSR-133使用happens-before的概念來(lái)指定兩個(gè)操作之間的執(zhí)行順序翅睛。由于這兩個(gè)操作可以在一個(gè)線程之內(nèi)声搁,也可以是在不同線程之間。

因此捕发,JMM可以通過(guò)happens-before關(guān)系向程序員提供跨線程的內(nèi)存可見(jiàn)性保證(如果A線程的寫(xiě)操作a與B線程的讀操作b之間存在happens-before關(guān)系疏旨,盡管a操作和b操作在不同的線程中執(zhí)行,但JMM向程序員保證a操作將對(duì)b操作可見(jiàn))扎酷。

具體的定義為:

1)如果一個(gè)操作happens-before另一個(gè)操作檐涝,那么第一個(gè)操作的執(zhí)行結(jié)果將對(duì)第二個(gè)操作可見(jiàn),而且第一個(gè)操作的執(zhí)行順序排在第二個(gè)操作之前法挨。

2)兩個(gè)操作之間存在happens-before關(guān)系谁榜,并不意味著Java平臺(tái)的具體實(shí)現(xiàn)必須要按照happens-before關(guān)系指定的順序來(lái)執(zhí)行。如果重排序之后的執(zhí)行結(jié)果凡纳,與按happens-before關(guān)系來(lái)執(zhí)行的結(jié)果一致窃植,那么這種重排序并不非法(也就是說(shuō),JMM允許這種重排序)荐糜。

上面的(1)是JMM對(duì)程序員的承諾撕瞧。從程序員的角度來(lái)說(shuō)陵叽,可以這樣理解happens-before關(guān)系:如果A happens-before B,那么Java內(nèi)存模型將向程序員保證——A操作的結(jié)果將對(duì)B可見(jiàn)丛版,且A的執(zhí)行順序排在B之前巩掺。注意,這只是Java內(nèi)存模型向程序員做出的保證页畦!

上面的(2)是JMM對(duì)編譯器和處理器重排序的約束原則胖替。正如前面所言,JMM其實(shí)是在遵循一個(gè)基本原則:只要不改變程序的執(zhí)行結(jié)果(指的是單線程程序和正確同步的多線程程序)豫缨,編譯器和處理器怎么優(yōu)化都行独令。JMM這么做的原因是:程序員對(duì)于這兩個(gè)操作是否真的被重排序并不關(guān)心,程序員關(guān)心的是程序執(zhí)行時(shí)的語(yǔ)義不能被改變(即執(zhí)行結(jié)果不能被改變)好芭。

因此燃箭,happens-before關(guān)系本質(zhì)上和as-if-serial語(yǔ)義是一回事。

下面來(lái)比較一下as-if-serial和happens-before:

as-if-serial ? VS ? happens-before

as-if-serial語(yǔ)義保證單線程內(nèi)程序的執(zhí)行結(jié)果不被改變舍败,happens-before關(guān)系保證正確同步的多線程程序的執(zhí)行結(jié)果不被改變招狸。

as-if-serial語(yǔ)義給編寫(xiě)單線程程序的程序員創(chuàng)造了一個(gè)幻境:?jiǎn)尉€程程序是按程序的順序來(lái)執(zhí)行的。happens-before關(guān)系給編寫(xiě)正確同步的多線程程序的程序員創(chuàng)造了一個(gè)幻境:正確同步的多線程程序是按happens-before指定的順序來(lái)執(zhí)行的邻薯。

as-if-serial語(yǔ)義和happens-before這么做的目的裙戏,都是為了在不改變程序執(zhí)行結(jié)果的前提下,盡可能地提高程序執(zhí)行的并行度厕诡。

4.2 具體規(guī)則

具體的一共有八項(xiàng)規(guī)則:

程序順序規(guī)則:一個(gè)線程中的每個(gè)操作累榜,happens-before于該線程中的任意后續(xù)操作。

監(jiān)視器鎖規(guī)則:對(duì)一個(gè)鎖的解鎖灵嫌,happens-before于隨后對(duì)這個(gè)鎖的加鎖壹罚。

volatile變量規(guī)則:對(duì)一個(gè)volatile域的寫(xiě),happens-before于任意后續(xù)對(duì)這個(gè)volatile域的讀寿羞。

傳遞性:如果A happens-before B渔嚷,且B happens-before C,那么A happens-before C稠曼。

start()規(guī)則:如果線程A執(zhí)行操作ThreadB.start()(啟動(dòng)線程B)形病,那么A線程的ThreadB.start()操作happens-before于線程B中的任意操作。

join()規(guī)則:如果線程A執(zhí)行操作ThreadB.join()并成功返回霞幅,那么線程B中的任意操作happens-before于線程A從ThreadB.join()操作成功返回漠吻。

程序中斷規(guī)則:對(duì)線程interrupted()方法的調(diào)用先行于被中斷線程的代碼檢測(cè)到中斷時(shí)間的發(fā)生。

對(duì)象finalize規(guī)則:一個(gè)對(duì)象的初始化完成(構(gòu)造函數(shù)執(zhí)行結(jié)束)先行于發(fā)生它的finalize()方法的開(kāi)始司恳。

下面以一個(gè)具體的例子來(lái)講下如何使用這些規(guī)則進(jìn)行推論:

依舊以上面計(jì)算圓面積的進(jìn)行描述途乃。利用程序順序規(guī)則(規(guī)則1)存在三個(gè)happens-before關(guān)系:1. A happens-before B;2. B happens-before C;3. A happens-before C扔傅。這里的第三個(gè)關(guān)系是利用傳遞性進(jìn)行推論的耍共。

A happens-before B,定義1要求A執(zhí)行結(jié)果對(duì)B可見(jiàn)烫饼,并且A操作的執(zhí)行順序在B操作之前,但與此同時(shí)利用定義中的第二條试读,A,B操作彼此不存在數(shù)據(jù)依賴(lài)性杠纵,兩個(gè)操作的執(zhí)行順序?qū)ψ罱K結(jié)果都不會(huì)產(chǎn)生影響,在不改變最終結(jié)果的前提下钩骇,允許A比藻,B兩個(gè)操作重排序,即happens-before關(guān)系并不代表了最終的執(zhí)行順序倘屹。

5. 總結(jié)

上面已經(jīng)聊了關(guān)于JMM的兩個(gè)方面:

JMM的抽象結(jié)構(gòu)(主內(nèi)存和線程工作內(nèi)存)银亲;

重排序以及happens-before規(guī)則。

接下來(lái)纽匙,我們來(lái)做一個(gè)總結(jié)务蝠。從兩個(gè)方面進(jìn)行考慮。

如果讓我們?cè)O(shè)計(jì)JMM應(yīng)該從哪些方面考慮烛缔,也就是說(shuō)JMM承擔(dān)哪些功能馏段;

happens-before與JMM的關(guān)系;

由于JMM力穗,多線程情況下可能會(huì)出現(xiàn)哪些問(wèn)題?

5.1 JMM的設(shè)計(jì)

JMM是語(yǔ)言級(jí)的內(nèi)存模型气嫁,在我的理解中JMM處于中間層当窗,包含了兩個(gè)方面:(1)內(nèi)存模型;(2)重排序以及happens-before規(guī)則寸宵。同時(shí)崖面,為了禁止特定類(lèi)型的重排序會(huì)對(duì)編譯器和處理器指令序列加以控制。

而上層會(huì)有基于JMM的關(guān)鍵字和J.U.C包下的一些具體類(lèi)用來(lái)方便程序員能夠迅速高效率的進(jìn)行并發(fā)編程梯影。站在JMM設(shè)計(jì)者的角度巫员,在設(shè)計(jì)JMM時(shí)需要考慮兩個(gè)關(guān)鍵因素:

程序員對(duì)內(nèi)存模型的使用

程序員希望內(nèi)存模型易于理解、易于編程甲棍。程序員希望基于一個(gè)強(qiáng)內(nèi)存模型來(lái)編寫(xiě)代碼简识。

編譯器和處理器對(duì)內(nèi)存模型的實(shí)現(xiàn)

編譯器和處理器希望內(nèi)存模型對(duì)它們的束縛越少越好,這樣它們就可以做盡可能多的優(yōu)化來(lái)提高性能感猛。編譯器和處理器希望實(shí)現(xiàn)一個(gè)弱內(nèi)存模型七扰。

另外還要一個(gè)特別有意思的事情就是關(guān)于重排序問(wèn)題,更簡(jiǎn)單的說(shuō)陪白,重排序可以分為兩類(lèi):

會(huì)改變程序執(zhí)行結(jié)果的重排序颈走。

不會(huì)改變程序執(zhí)行結(jié)果的重排序。

JMM對(duì)這兩種不同性質(zhì)的重排序咱士,采取了不同的策略立由,如下轧钓。

對(duì)于會(huì)改變程序執(zhí)行結(jié)果的重排序,JMM要求編譯器和處理器必須禁止這種重排序锐膜。

對(duì)于不會(huì)改變程序執(zhí)行結(jié)果的重排序毕箍,JMM對(duì)編譯器和處理器不做要求(JMM允許這種重排序)

JMM的設(shè)計(jì)圖為:

從圖可以看出:

JMM向程序員提供的happens-before規(guī)則能滿足程序員的需求。JMM的happens-before規(guī)則不但簡(jiǎn)單易懂枣耀,而且也向程序員提供了足夠強(qiáng)的內(nèi)存可見(jiàn)性保證(有些內(nèi)存可見(jiàn)性保證其實(shí)并不一定真實(shí)存在霉晕,比如上面的A happens-before B)。

JMM對(duì)編譯器和處理器的束縛已經(jīng)盡可能少捞奕。從上面的分析可以看出牺堰,JMM其實(shí)是在遵循一個(gè)基本原則:只要不改變程序的執(zhí)行結(jié)果(指的是單線程程序和正確同步的多線程程序),編譯器和處理器怎么優(yōu)化都行颅围。

例如伟葫,如果編譯器經(jīng)過(guò)細(xì)致的分析后,認(rèn)定一個(gè)鎖只會(huì)被單個(gè)線程訪問(wèn)院促,那么這個(gè)鎖可以被消除筏养。

再如,如果編譯器經(jīng)過(guò)細(xì)致的分析后常拓,認(rèn)定一個(gè)volatile變量只會(huì)被單個(gè)線程訪問(wèn)渐溶,那么編譯器可以把這個(gè)volatile變量當(dāng)作一個(gè)普通變量來(lái)對(duì)待。這些優(yōu)化既不會(huì)改變程序的執(zhí)行結(jié)果弄抬,又能提高程序的執(zhí)行效率茎辐。

5.2 happens-before與JMM的關(guān)系

一個(gè)happens-before規(guī)則對(duì)應(yīng)于一個(gè)或多個(gè)編譯器和處理器重排序規(guī)則。對(duì)于Java程序員來(lái)說(shuō)掂恕,happens-before規(guī)則簡(jiǎn)單易懂拖陆,它避免Java程序員為了理解JMM提供的內(nèi)存可見(jiàn)性保證而去學(xué)習(xí)復(fù)雜的重排序規(guī)則以及這些規(guī)則的具體實(shí)現(xiàn)方法

5.3 今后可能需要關(guān)注的問(wèn)題

從上面內(nèi)存抽象結(jié)構(gòu)來(lái)說(shuō),可能出在數(shù)據(jù)“臟讀”的現(xiàn)象懊亡,這就是數(shù)據(jù)可見(jiàn)性的問(wèn)題依啰,另外,重排序在多線程中不注意的話也容易存在一些問(wèn)題店枣,比如一個(gè)很經(jīng)典的問(wèn)題就是DCL(雙重檢驗(yàn)鎖)速警,這就是需要禁止重排序,另外鸯两,在多線程下原子操作例如i++不加以注意的也容易出現(xiàn)線程安全的問(wèn)題坏瞄。

但總的來(lái)說(shuō),在多線程開(kāi)發(fā)時(shí)需要從原子性甩卓,有序性鸠匀,可見(jiàn)性三個(gè)方面進(jìn)行考慮。J.U.C包下的并發(fā)工具類(lèi)和并發(fā)容器也是需要花時(shí)間去掌握的逾柿,這些東西在以后得文章中多會(huì)一一進(jìn)行討論缀棍。

近期干貨文章推薦

冒泡排序

快速排序

直接插入排序

算法之深度優(yōu)先搜索

一組考算法的面試題(尋求最優(yōu)解)

一致性哈希算法學(xué)習(xí)及JAVA代碼實(shí)現(xiàn)分析

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末宅此,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子爬范,更是在濱河造成了極大的恐慌父腕,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,470評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件青瀑,死亡現(xiàn)場(chǎng)離奇詭異璧亮,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)斥难,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)枝嘶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人哑诊,你說(shuō)我怎么就攤上這事群扶。” “怎么了镀裤?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,577評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵竞阐,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我暑劝,道長(zhǎng)骆莹,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,176評(píng)論 1 292
  • 正文 為了忘掉前任担猛,我火速辦了婚禮幕垦,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘毁习。我一直安慰自己智嚷,他們只是感情好卖丸,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布纺且。 她就那樣靜靜地躺著,像睡著了一般稍浆。 火紅的嫁衣襯著肌膚如雪载碌。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,155評(píng)論 1 299
  • 那天衅枫,我揣著相機(jī)與錄音嫁艇,去河邊找鬼。 笑死弦撩,一個(gè)胖子當(dāng)著我的面吹牛步咪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播益楼,決...
    沈念sama閱讀 40,041評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼猾漫,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼点晴!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起悯周,我...
    開(kāi)封第一講書(shū)人閱讀 38,903評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤粒督,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后禽翼,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體屠橄,經(jīng)...
    沈念sama閱讀 45,319評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評(píng)論 2 332
  • 正文 我和宋清朗相戀三年闰挡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了锐墙。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,703評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡解总,死狀恐怖贮匕,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情花枫,我是刑警寧澤刻盐,帶...
    沈念sama閱讀 35,417評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站劳翰,受9級(jí)特大地震影響敦锌,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜佳簸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評(píng)論 3 325
  • 文/蒙蒙 一乙墙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧生均,春花似錦听想、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,664評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至佩脊,卻和暖如春蛙粘,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背威彰。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,818評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工出牧, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人歇盼。 一個(gè)月前我還...
    沈念sama閱讀 47,711評(píng)論 2 368
  • 正文 我出身青樓舔痕,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子伯复,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評(píng)論 2 353