可見(jiàn)性、原子性和有序性的問(wèn)題

????????CPU械馆、內(nèi)存以及I/O設(shè)備都在不斷迭代胖眷,不斷朝著更快的方向努力。但是霹崎,在這個(gè)快速發(fā)展的過(guò)程中珊搀,有一個(gè)核心矛盾一直存在,即三者之間的速度差異尾菇。程序里大部分語(yǔ)句都要訪問(wèn)內(nèi)存境析,有些還要訪問(wèn)I/O,根據(jù)木桶原理派诬,程序整體的性能取決于最慢的操作——讀寫I/O設(shè)備劳淆,也就是說(shuō)單方面提高CPU性能是無(wú)效的。為了合理利用CPU的高性能默赂,平衡這三者的速度差異沛鸵,計(jì)算機(jī)體系機(jī)構(gòu)、操作系統(tǒng)缆八、編譯程序都做出了貢獻(xiàn)曲掰,主要體現(xiàn)為:

? ? ? ? 1、CPU增加了緩存奈辰,以均衡與內(nèi)存的速度差異栏妖;

? ? ? ? 2、操作系統(tǒng)增加了進(jìn)程奖恰、線程吊趾,以分時(shí)復(fù)用CPU宛裕,進(jìn)而均衡CPU與I/O設(shè)備的速度差異;

? ? ? ? 3论泛、編譯程序優(yōu)化指令執(zhí)行次序续滋,使得緩存能夠得到更加合理地利用。

增加緩存孵奶,帶來(lái)了可見(jiàn)性的問(wèn)題

? ? ? ? 在單核時(shí)代,所有的線程都是在一顆CPU上執(zhí)行蜡峰,CPU緩存與內(nèi)存的數(shù)據(jù)一致性很容易解決了袁,因?yàn)樗械木€程都在同一個(gè)CPU運(yùn)行,即操作的都是同一個(gè)CPU的內(nèi)存湿颅,故一個(gè)線程對(duì)緩存的寫载绿,對(duì)另外一個(gè)線程來(lái)說(shuō)一定是可見(jiàn)的。如圖:


單核

? ? ? ? 由圖可知油航,當(dāng)線程A更新共享變量V的值崭庸,那么線程B之后再訪問(wèn)變量V,得到一定是V的最新值谊囚。

? ? ? ? 多核時(shí)代怕享,每個(gè)CPU都有各自的緩存,當(dāng)多個(gè)線程在不同的CPU上執(zhí)行時(shí)镰踏,這些線程操作的是不同的CPU緩存函筋,故可見(jiàn)性就不是那么容易保證了。


多核

? ? ? ? 一個(gè)線程對(duì)共享變量的修改奠伪,另外一個(gè)線程能夠立刻看到跌帐,稱為可見(jiàn)性。

線程切換绊率,帶來(lái)原子性問(wèn)題

? ? ? ? 操作系統(tǒng)允許某個(gè)進(jìn)程執(zhí)行一小段時(shí)間谨敛,過(guò)了這一小段時(shí)間,操作系統(tǒng)就會(huì)重新選擇一個(gè)進(jìn)程來(lái)執(zhí)行(任務(wù)切換)滤否,這小段時(shí)間稱為”時(shí)間片“脸狸。在一個(gè)時(shí)間片內(nèi),如果一個(gè)進(jìn)程進(jìn)行一個(gè)IO操作顽聂,例如讀個(gè)文件肥惭,這個(gè)時(shí)候該進(jìn)程可以把自己標(biāo)記為”休眠狀態(tài)“并出讓CPU的使用權(quán),待文件讀進(jìn)內(nèi)存紊搪,操作系統(tǒng)會(huì)把這個(gè)休眠的進(jìn)程喚醒蜜葱,喚醒后的進(jìn)程就有機(jī)會(huì)重新獲得CPU的使用權(quán)了。進(jìn)程在等待IO時(shí)之所以會(huì)釋放CPU使用權(quán)耀石,是為了讓CPU在這段時(shí)間里可以做別的事情牵囤,這樣一來(lái)CPU的使用率就上來(lái)了爸黄;此外,如果這時(shí)有另外一個(gè)進(jìn)程也讀文件揭鳞,讀文件的操作就會(huì)排隊(duì)炕贵,磁盤驅(qū)動(dòng)在完成一個(gè)進(jìn)程的讀操作后,發(fā)現(xiàn)有排隊(duì)的任務(wù)野崇,就會(huì)立即啟動(dòng)下一個(gè)讀操作称开,這樣IO的使用率也上來(lái)了。

? ? ? ? 早期的操作系統(tǒng)基于進(jìn)程來(lái)調(diào)度CPU乓梨,不同進(jìn)程間是不共享內(nèi)存空間的鳖轰,所以進(jìn)程要做任務(wù)切換就要切換內(nèi)存映射地址,而一個(gè)進(jìn)程創(chuàng)建的所有線程扶镀,都是共享一個(gè)內(nèi)存空間的蕴侣,所以線程做任務(wù)切換成本就很低了。現(xiàn)代的操作系統(tǒng)都基于更輕量的線程來(lái)調(diào)度臭觉,現(xiàn)在提到的”任務(wù)切換“都是指”線程切換“昆雀。

? ? ? ? Java并發(fā)程序都是基于多線程的,自然會(huì)涉及到任務(wù)切換蝠筑,任務(wù)切換是并發(fā)編程里詭異Bug的源頭之一狞膘。任務(wù)切換的時(shí)機(jī)大多數(shù)是在時(shí)間片結(jié)束的時(shí)候,現(xiàn)在基本都是使用高級(jí)語(yǔ)言編程什乙,高級(jí)語(yǔ)言一條語(yǔ)句往往需要多條CPU指令完成客冈,例如count++,至少需要三條cpu指令來(lái)完成稳强。操作系統(tǒng)做任務(wù)切換场仲,可以發(fā)生在任何一條CPU指令執(zhí)行完,注意退疫,不是高級(jí)語(yǔ)言里的一條語(yǔ)句渠缕。

? ? ? ? 所謂的原子性,就是指一個(gè)或者多個(gè)操作在CPU執(zhí)行的過(guò)程中不被中斷的特性褒繁。CPU能保證的原子操作是CPU指令級(jí)別的亦鳞,而不是高級(jí)語(yǔ)言的操作符。

編譯優(yōu)化棒坏,帶來(lái)了有序性問(wèn)題

? ? ? ? 有序性燕差,指的是程序按照代碼的先后順序執(zhí)行。編譯器為了優(yōu)化性能坝冕,有時(shí)候會(huì)改變程序中語(yǔ)句的先后順序徒探,但是不影響程序的最終結(jié)果。不過(guò)有時(shí)候編譯器及解釋器的優(yōu)化可能導(dǎo)致意想不到的Bug喂窟。例如:雙重檢查再加鎖的方式實(shí)現(xiàn)的單例模式测暗。

????????public class Singleton {

? ? ? ? ????????static Singleton instance;

? ? ? ????????? static Singleton getInstance() {

? ? ? ? ? ? ? ? ????????if(instance? ? ==? ? null) {

? ? ? ? ? ? ? ? ? ? ? ? ????????synchronized(Singleton.class) {

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ????????? if(instance? ? ==? ? null) {

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ????????instance? ? =? ? new Singleton();

????????????????????????????????????????}

????????????????????????????????}

? ? ? ? ? ? ? ? ????????return instance;

? ? ? ? ? ? ? ? ? }

?????????}

? ? ? ? 假設(shè)有兩個(gè)線程A央串、B同時(shí)調(diào)用getInstance()方法,他們會(huì)同時(shí)發(fā)現(xiàn)instance == null碗啄,于是同時(shí)對(duì)Singleton加鎖质和,此時(shí)JVM保證只有一個(gè)線程能夠加鎖成功,假設(shè)線程A加鎖成功稚字,線程B處于等待狀態(tài)饲宿。線程A會(huì)創(chuàng)建一個(gè)Sington實(shí)例,之后釋放鎖胆描,鎖釋放后褒傅,線程B被喚醒,線程B再次嘗試加鎖袄友,此時(shí)是可以加鎖成功的,加鎖成功后霹菊,線程B檢查instance == null時(shí)會(huì)發(fā)現(xiàn)剧蚣,已經(jīng)創(chuàng)建過(guò)Singleton實(shí)例了,所以線程B不會(huì)在創(chuàng)建一個(gè)Singleton實(shí)例旋廷。

? ? ? ? 這個(gè)過(guò)程看上去沒(méi)什么問(wèn)題鸠按,但是問(wèn)題出在new操作上,new操作分為如下的步驟:

? ? ? ? ? ? ? ? 1饶碘、分配一個(gè)內(nèi)存M目尖;

? ? ? ? ? ? ? ? 2、在內(nèi)存M上初始化Singleton對(duì)象扎运;

? ? ? ? ? ? ? ? 3瑟曲、然后M的地址賦值給instant變量;

? ? ? ? 但是經(jīng)過(guò)編譯器優(yōu)化后豪治,可能new操作的執(zhí)行順序可能會(huì)變成這樣:1->3->2洞拨,當(dāng)先執(zhí)行的線程執(zhí)行至3時(shí),恰好發(fā)生了線程切換负拟,切換到別的線程烦衣,別的線程執(zhí)行到了第一個(gè)if語(yǔ)句,此時(shí)判斷結(jié)果為false掩浙,直接返回instance實(shí)例花吟,而instance實(shí)例還沒(méi)有初始化,訪問(wèn)instance實(shí)例的時(shí)候會(huì)出現(xiàn)空指針異常厨姚。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末衅澈,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子谬墙,更是在濱河造成了極大的恐慌矾麻,老刑警劉巖纱耻,帶你破解...
    沈念sama閱讀 219,427評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異险耀,居然都是意外死亡弄喘,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門甩牺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)蘑志,“玉大人,你說(shuō)我怎么就攤上這事贬派〖钡” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,747評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵搞乏,是天一觀的道長(zhǎng)波桩。 經(jīng)常有香客問(wèn)我,道長(zhǎng)请敦,這世上最難降的妖魔是什么镐躲? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,939評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮侍筛,結(jié)果婚禮上萤皂,老公的妹妹穿的比我還像新娘。我一直安慰自己匣椰,他們只是感情好裆熙,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著禽笑,像睡著了一般入录。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上佳镜,一...
    開(kāi)封第一講書(shū)人閱讀 51,737評(píng)論 1 305
  • 那天纷跛,我揣著相機(jī)與錄音,去河邊找鬼邀杏。 笑死贫奠,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的望蜡。 我是一名探鬼主播唤崭,決...
    沈念sama閱讀 40,448評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼脖律!你這毒婦竟也來(lái)了谢肾?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,352評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤小泉,失蹤者是張志新(化名)和其女友劉穎芦疏,沒(méi)想到半個(gè)月后冕杠,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,834評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡酸茴,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評(píng)論 3 338
  • 正文 我和宋清朗相戀三年分预,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片薪捍。...
    茶點(diǎn)故事閱讀 40,133評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡笼痹,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出酪穿,到底是詐尸還是另有隱情凳干,我是刑警寧澤,帶...
    沈念sama閱讀 35,815評(píng)論 5 346
  • 正文 年R本政府宣布被济,位于F島的核電站救赐,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏只磷。R本人自食惡果不足惜经磅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望喳瓣。 院中可真熱鬧,春花似錦赞别、人聲如沸畏陕。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,022評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)惠毁。三九已至,卻和暖如春崎页,著一層夾襖步出監(jiān)牢的瞬間鞠绰,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,147評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工飒焦, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蜈膨,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,398評(píng)論 3 373
  • 正文 我出身青樓牺荠,卻偏偏與公主長(zhǎng)得像翁巍,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子休雌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評(píng)論 2 355

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