深入理解并發(fā)編程和歸納總結(jié)

1踪区、Java內(nèi)存模型(JMM)

從抽象的角度來看叹阔,JMM定義了線程和主內(nèi)存之間的抽象關(guān)系:線程之間的共享變量存儲在主內(nèi)存(Main Memory)中师妙,每個線程都有一個私有的本地內(nèi)存(Local Memory)诗祸,本地內(nèi)存中存儲了該線程以讀/寫共享變量的副本血久。本地內(nèi)存是JMM的一個抽象概念突照,并不真實存在。它涵蓋了緩存氧吐、寫緩沖區(qū)讹蘑、寄存器以及其他的硬件和編譯器優(yōu)化。


image.png
image.png

2筑舅、可見性

  • 可見性是指當多個線程訪問同一個變量時座慰,一個線程修改了這個變量的值,其他線程能夠立即看得到修改的值翠拣。
  • 由于線程對變量的所有操作都必須在工作內(nèi)存中進行版仔,而不能直接讀寫主內(nèi)存中的變量,那么對于共享變量V误墓,它們首先是在自己的工作內(nèi)存蛮粮,之后再同步到主內(nèi)存∮派眨可是并不會及時的刷到主存中蝉揍,而是會有一定時間差。很明顯畦娄,這個時候線程 A 對變量 V 的操作對于線程 B 而言就不具備可見性了 。
  • 要解決共享對象可見性這個問題弊仪,我們可以使用volatile關(guān)鍵字或者是加鎖熙卡。

3、原子性

  • 原子性:即一個操作或者多個操作 要么全部執(zhí)行并且執(zhí)行的過程不會被任何因素打斷励饵,要么就都不執(zhí)行驳癌。
  • 我們都知道CPU資源的分配都是以線程為單位的,并且是分時調(diào)用,操作系統(tǒng)允許某個進程執(zhí)行一小段時間,例如 50 毫秒役听,過了 50 毫秒操作系統(tǒng)就會重新選擇一個進程來執(zhí)行(我們稱為“任務(wù)切換”)颓鲜,這個 50 毫秒稱為“時間片”。而任務(wù)的切換大多數(shù)是在時間片段結(jié)束以后,
  • 那么線程切換為什么會帶來bug呢典予?因為操作系統(tǒng)做任務(wù)切換甜滨,可以發(fā)生在任何一條CPU 指令執(zhí)行完!注意瘤袖,是 CPU 指令衣摩,CPU 指令,CPU 指令捂敌,而不是高級語言里的一條語句艾扮。比如count++既琴,在java里就是一句話,但高級語言里一條語句往往需要多條 CPU 指令完成泡嘴。其實count++包含了三個CPU指令甫恩!

4、volatile特性

可以把對volatile變量的單個讀/寫酌予,看成是使用同一個鎖對這些單個讀/寫操作做了同步

image.png

可以看成

image.png
  • 所以volatile變量自身具有下列特性:
  • 可見性磺箕。對一個volatile變量的讀,總是能看到(任意線程)對這個volatile變量最后的寫入霎终。
  • 原子性:對任意單個volatile變量的讀/寫具有原子性滞磺,但類似于volatile++這種復(fù)合操作不具有原子性。
  • volatile雖然能保證執(zhí)行完及時把變量刷到主內(nèi)存中莱褒,但對于count++這種非原子性击困、多指令的情況,由于線程切換广凸,線程A剛把count=0加載到工作內(nèi)存阅茶,線程B就可以開始工作了,這樣就會導(dǎo)致線程A和B執(zhí)行完的結(jié)果都是1谅海,都寫到主內(nèi)存中脸哀,主內(nèi)存的值還是1不是2

5、volatile的實現(xiàn)原理

  • 通過對OpenJDK中的unsafe.cpp源碼的分析扭吁,會發(fā)現(xiàn)被volatile關(guān)鍵字修飾的變量會存在一個“l(fā)ock:”的前綴撞蜂。
  • Lock前綴,Lock不是一種內(nèi)存屏障侥袜,但是它能完成類似內(nèi)存屏障的功能蝌诡。Lock會對CPU總線和高速緩存加鎖,可以理解為CPU指令級的一種鎖枫吧。
  • 同時該指令會將當前處理器緩存行的數(shù)據(jù)直接寫會到系統(tǒng)內(nèi)存中浦旱,且這個寫回內(nèi)存的操作會使在其他CPU里緩存了該地址的數(shù)據(jù)無效。

6九杂、synchronized的實現(xiàn)原理

image.png
image.png
  • Synchronized在JVM里的實現(xiàn)都是基于進入和退出Monitor對象來實現(xiàn)方法同步和代碼塊同步颁湖,雖然具體實現(xiàn)細節(jié)不一樣,但是都可以通過成對的MonitorEnter和MonitorExit指令來實現(xiàn)例隆。
  • 對同步塊甥捺,MonitorEnter指令插入在同步代碼塊的開始位置,當代碼執(zhí)行到該指令時裳擎,將會嘗試獲取該對象Monitor的所有權(quán)涎永,即嘗試獲得該對象的鎖,而monitorExit指令則插入在方法結(jié)束處和異常處,JVM保證每個MonitorEnter必須有對應(yīng)的MonitorExit羡微。
  • 對同步方法谷饿,從同步方法反編譯的結(jié)果來看,方法的同步并沒有通過指令monitorenter和monitorexit來實現(xiàn)妈倔,相對于普通方法博投,其常量池中多了ACC_SYNCHRONIZED標示符。
  • JVM就是根據(jù)該標示符來實現(xiàn)方法的同步的:當方法被調(diào)用時盯蝴,調(diào)用指令將會檢查方法的 ACC_SYNCHRONIZED 訪問標志是否被設(shè)置毅哗,如果設(shè)置了,執(zhí)行線程將先獲取monitor捧挺,獲取成功之后才能執(zhí)行方法體虑绵,方法執(zhí)行完后再釋放monitor。在方法執(zhí)行期間闽烙,其他任何線程都無法再獲得同一個monitor對象翅睛。
  • synchronized使用的鎖是存放在Java對象頭里面,
image.png

具體位置是對象頭里面的MarkWord黑竞,MarkWord里默認數(shù)據(jù)是存儲對象的HashCode等信息捕发,

image.png

但是會隨著對象的運行改變而發(fā)生變化,不同的鎖狀態(tài)對應(yīng)著不同的記錄存儲方式

image.png

7很魂、自旋鎖

原理

  • 自旋鎖原理非常簡單扎酷,如果持有鎖的線程能在很短時間內(nèi)釋放鎖資源,那么那些等待競爭鎖的線程就不需要做內(nèi)核態(tài)和用戶態(tài)之間的切換進入阻塞掛起狀態(tài)遏匆,它們只需要等一等(自旋)法挨,等持有鎖的線程釋放鎖后即可立即獲取鎖,這樣就避免用戶線程和內(nèi)核的切換的消耗幅聘。
    但是線程自旋是需要消耗CPU的坷剧,說白了就是讓CPU在做無用功,線程不能一直占用CPU自旋做無用功喊暖,所以需要設(shè)定一個自旋等待的最大時間。
    如果持有鎖的線程執(zhí)行的時間超過自旋等待的最大時間扔沒有釋放鎖撕瞧,就會導(dǎo)致其它爭用鎖的線程在最大等待時間內(nèi)還是獲取不到鎖陵叽,這時爭用線程會停止自旋進入阻塞狀態(tài)。

自旋鎖的優(yōu)缺點

  • 自旋鎖盡可能的減少線程的阻塞丛版,這對于鎖的競爭不激烈巩掺,且占用鎖時間非常短的代碼塊來說性能能大幅度的提升,因為自旋的消耗會小于線程阻塞掛起操作的消耗页畦!
    但是如果鎖的競爭激烈胖替,或者持有鎖的線程需要長時間占用鎖執(zhí)行同步塊,這時候就不適合使用自旋鎖了,因為自旋鎖在獲取鎖前一直都是占用cpu做無用功独令,占著XX不XX端朵,線程自旋的消耗大于線程阻塞掛起操作的消耗,其它需要cup的線程又不能獲取到cpu燃箭,造成cpu的浪費冲呢。

自旋鎖時間閾值

  • 自旋鎖的目的是為了占著CPU的資源不釋放,等到獲取到鎖立即進行處理招狸。但是如何去選擇自旋的執(zhí)行時間呢敬拓?如果自旋執(zhí)行時間太長,會有大量的線程處于自旋狀態(tài)占用CPU資源裙戏,進而會影響整體系統(tǒng)的性能乘凸。因此自旋次數(shù)很重要
  • JVM對于自旋次數(shù)的選擇,jdk1.5默認為10次累榜,在1.6引入了適應(yīng)性自旋鎖营勤,適應(yīng)性自旋鎖意味著自旋的時間不在是固定的了,而是由前一次在同一個鎖上的自旋時間以及鎖的擁有者的狀態(tài)來決定信柿,基本認為一個線程上下文切換的時間是最佳的一個時間冀偶。
    JDK1.6中-XX:+UseSpinning開啟自旋鎖; JDK1.7后渔嚷,去掉此參數(shù)进鸠,由jvm控制;
image.png

8形病、鎖的狀態(tài)

一共有四種狀態(tài)客年,無鎖狀態(tài),偏向鎖狀態(tài)漠吻,輕量級鎖狀態(tài)和重量級鎖狀態(tài)量瓜,它會隨著競爭情況逐漸升級。鎖可以升級但不能降級途乃,目的是為了提高獲得鎖和釋放鎖的效率绍傲。

偏向鎖
引入背景:大多數(shù)情況下鎖不僅不存在多線程競爭,而且總是由同一線程多次獲得耍共,為了讓線程獲得鎖的代價更低而引入了偏向鎖烫饼,減少不必要的CAS操作。
偏向鎖试读,顧名思義杠纵,它會偏向于第一個訪問鎖的線程,如果在運行過程中钩骇,同步鎖只有一個線程訪問比藻,不存在多線程爭用的情況铝量,則線程是不需要觸發(fā)同步的,減少加鎖/解鎖的一些CAS操作(比如等待隊列的一些CAS操作)银亲,這種情況下慢叨,就會給線程加一個偏向鎖。 如果在運行過程中群凶,遇到了其他線程搶占鎖插爹,則持有偏向鎖的線程會被掛起,JVM會消除它身上的偏向鎖请梢,將鎖恢復(fù)到標準的輕量級鎖赠尾。它通過消除資源無競爭情況下的同步原語,進一步提高了程序的運行性能毅弧。

  • 偏向鎖獲取過程:
    步驟1气嫁、 訪問Mark Word中偏向鎖的標識是否設(shè)置成1,鎖標志位是否為01够坐,確認為可偏向狀態(tài)寸宵。
    步驟2、 如果為可偏向狀態(tài)元咙,則測試線程ID是否指向當前線程梯影,如果是,進入步驟5庶香,否則進入步驟3甲棍。
    步驟3、 如果線程ID并未指向當前線程赶掖,則通過CAS操作競爭鎖感猛。如果競爭成功,則將Mark Word中線程ID設(shè)置為當前線程ID奢赂,然后執(zhí)行5陪白;如果競爭失敗,執(zhí)行4膳灶。
    步驟4咱士、 如果CAS獲取偏向鎖失敗,則表示有競爭轧钓。當?shù)竭_全局安全點(safepoint)時獲得偏向鎖的線程被掛起司致,偏向鎖升級為輕量級鎖,然后被阻塞在安全點的線程繼續(xù)往下執(zhí)行同步代碼聋迎。(撤銷偏向鎖的時候會導(dǎo)致stop the word)
    步驟5、 執(zhí)行同步代碼枣耀。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末霉晕,一起剝皮案震驚了整個濱河市庭再,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌牺堰,老刑警劉巖拄轻,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異伟葫,居然都是意外死亡恨搓,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門筏养,熙熙樓的掌柜王于貴愁眉苦臉地迎上來斧抱,“玉大人,你說我怎么就攤上這事渐溶』云郑” “怎么了?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵茎辐,是天一觀的道長宪郊。 經(jīng)常有香客問我,道長拖陆,這世上最難降的妖魔是什么弛槐? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮依啰,結(jié)果婚禮上乎串,老公的妹妹穿的比我還像新娘。我一直安慰自己孔飒,他們只是感情好灌闺,可當我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著坏瞄,像睡著了一般桂对。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鸠匀,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天蕉斜,我揣著相機與錄音,去河邊找鬼缀棍。 笑死宅此,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的爬范。 我是一名探鬼主播父腕,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼青瀑!你這毒婦竟也來了璧亮?” 一聲冷哼從身側(cè)響起萧诫,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎枝嘶,沒想到半個月后帘饶,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡群扶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年及刻,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片竞阐。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡缴饭,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出馁菜,到底是詐尸還是另有隱情茴扁,我是刑警寧澤,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布汪疮,位于F島的核電站峭火,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏智嚷。R本人自食惡果不足惜卖丸,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望盏道。 院中可真熱鬧稍浆,春花似錦、人聲如沸猜嘱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽朗伶。三九已至弦撩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間论皆,已是汗流浹背益楼。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留点晴,地道東北人感凤。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像粒督,于是被迫代替她去往敵國和親陪竿。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,490評論 2 348

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