線程互斥同步問題

1. 鎖

為什么要用鎖: 線程進行的過程中隨時都有可能產(chǎn)生線程切換, 如果操作同一個變量,可能就會發(fā)生問題: 例如兩個線程對同一個變量i 各自進行10次自增操作, 得到的結(jié)果可能就不是20 , 原因是i++不是原子性的, 它是執(zhí)行了三條語句 Load i i+1 Store i, 在執(zhí)行Load i之后如果發(fā)生了線程切換, 下一個線程執(zhí)行完了 Load i i++ Store i 這時候 再切換回來, Load 到的i 還是下一個進程Store 之前的i

鎖的實現(xiàn),

1.屏蔽硬件中斷,

缺點: 1. 需要禁用硬件中斷,如果臨界區(qū)執(zhí)行時間很長,可能會導(dǎo)致其他硬件的任務(wù)無法正常執(zhí)行.比如網(wǎng)絡(luò)包,磁盤塊讀寫等
缺點: 2. 兩個CPU的情況下 ,處理起來比較麻煩, 因為CPU自己只能屏蔽自己的響應(yīng)中斷能力, 要去屏蔽其他CPU的硬件中斷,可能這時候其他CPU已經(jīng)執(zhí)行了臨界區(qū)代碼

2.軟件方法

P算法,D算法 ,解決兩個線程互斥問題, E M B(bakery) 算法,解決多個線程互斥問題
優(yōu)點: 只需要軟件就能解決
缺點: 忙等占用CPU資源,實現(xiàn)復(fù)雜

3.原子操作

系統(tǒng)提供原子操作CAS Exchange
int CAS(*p, except, update) 如果指針?biāo)傅奈恢门cexcept相同, 則更新為update, 并返回指針?biāo)傅奈恢玫闹?
如果指針?biāo)傅奈恢门cexcept不同, 則不更新, 并返回 指針?biāo)傅奈恢玫闹?/p>

2.信號量

基于上面3所說的原子操作實現(xiàn)
信號量是可以實現(xiàn)鎖的功能的

3. 管程

鎖 :
條件變量:

進入管程是互斥的
進入之后有很多條件變量, 每個變量都有一個等待隊列, 條件變量是可以釋放鎖的,

鎖的實現(xiàn)在1中已經(jīng)講過了
條件變量怎么實現(xiàn):
有wartingCount,和waitingQueue(注意waitingCount 和信號量是有區(qū)別的, waitingCount不需要)
wait方法, 和signal方法
wait方法: 釋放鎖 waitingCount++,TCB加入waitingQueue 通知操作系統(tǒng)發(fā)起線程調(diào)度
signal方法.if waitingCount > 0 { remove Thread t frome waitingQueue , weakup t }

4鎖的種類

樂觀鎖

認(rèn)為一般情況下沒有其他線程來搶占資源,只是在要更新的時候去判斷一下是否有其他線程修改了資源,
Java中: Atomic系列 CAS機制就是樂觀鎖

悲觀鎖

認(rèn)為一般情況下總是有其他線程來搶占資源,所以提前加鎖,
JAVA中, synchronize Lock 都是悲觀鎖

獨占鎖

加了鎖之后,只能由一個線程讀取和修改其中的共享資源,synchronize, ReentraindLock 都是獨占鎖

共享鎖

一個線程對一個數(shù)據(jù)加了共享鎖,其他線程也只能對它加共享鎖不能加獨占鎖,獲得共享鎖的線程只能讀數(shù)據(jù),不能修改數(shù)據(jù)
JAva中 ReentraintReadWriteLock就是共享鎖

互斥鎖

互斥鎖是獨占鎖的一種常規(guī)實現(xiàn),某一資源同時只允許一個線程對它訪問,有唯一性和排他性

讀寫鎖

讀寫鎖是共享鎖的一種實現(xiàn)
獨占寫鎖,共享讀鎖

公平鎖

公平鎖是指多個線程按照申請鎖的順序來獲取鎖晶通,這里類似排隊買票铡俐,先來的人先買翅阵,后來的人在隊尾排著紊选,這是公平的舆蝴。

/**
* 創(chuàng)建一個可重入鎖门岔,true 表示公平鎖库车,false 表示非公平鎖睁宰。默認(rèn)非公平鎖
*/
Lock lock = new ReentrantLock(true);
非公平鎖

非公平鎖是指多個線程獲取鎖的順序并不是按照申請鎖的順序襟企,有可能后申請的線程比先申請的線程優(yōu)先獲取鎖嘱么,在高并發(fā)環(huán)境下,有可能造成優(yōu)先級翻轉(zhuǎn)顽悼,或者饑餓的狀態(tài)(某個線程一直得不到鎖)曼振。
在 java 中 synchronized 關(guān)鍵字是非公平鎖,ReentrantLock默認(rèn)也是非公平鎖蔚龙。

/**
* 創(chuàng)建一個可重入鎖冰评,true 表示公平鎖,false 表示非公平鎖木羹。默認(rèn)非公平鎖
*/
Lock lock = new ReentrantLock(false);
可重入鎖

可重入鎖又稱之為遞歸鎖甲雅,是指同一個線程在外層方法獲取了鎖坑填,在進入內(nèi)層方法會自動獲取鎖抛人。
對于Java ReentrantLock而言, 他的名字就可以看出是一個可重入鎖。對于Synchronized而言脐瑰,也是一個可重入鎖妖枚。

敲黑板:可重入鎖的一個好處是可一定程度避免死鎖。

自旋鎖

旋鎖是指線程在沒有獲得鎖時不是被直接掛起苍在,而是執(zhí)行一個忙循環(huán)绝页,這個忙循環(huán)就是所謂的自旋荠商。自旋鎖的目的是為了減少線程被掛起的幾率,因為線程的掛起和喚醒也都是耗資源的操作续誉。

如果鎖被另一個線程占用的時間比較長莱没,即使自旋了之后當(dāng)前線程還是會被掛起,忙循環(huán)就會變成浪費系統(tǒng)資源的操作酷鸦,反而降低了整體性能郊愧。因此自旋鎖是不適應(yīng)鎖占用時間長的并發(fā)情況的。
在 Java 中井佑,AtomicInteger 類有自旋的操作,我們看一下代碼:


public final int getAndAddInt(Object o, long offset, int delta) {
    int v;
    do {
        v = getIntVolatile(o, offset);
    } while (!compareAndSwapInt(o, offset, v, v + delta));
    return v;
}

另外自適應(yīng)自旋鎖也需要了解一下眠寿。

在JDK1.6又引入了自適應(yīng)自旋躬翁,這個就比較智能了,自旋時間不再固定盯拱,由前一次在同一個鎖上的自旋時間以及鎖的擁有者的狀態(tài)來決定盒发。如果虛擬機認(rèn)為這次自旋也很有可能再次成功那就會自旋較多的時間,如果自旋很少成功狡逢,那以后可能就直接省略掉自旋過程宁舰,避免浪費處理器資源。

分段鎖

分段鎖 是一種鎖的設(shè)計奢浑,并不是具體的一種鎖蛮艰。

分段鎖設(shè)計目的是將鎖的粒度進一步細(xì)化,當(dāng)操作不需要更新整個數(shù)組的時候雀彼,就僅僅針對數(shù)組中的一項進行加鎖操作壤蚜。


image.png

在 Java 語言中 CurrentHashMap 底層就用了分段鎖,使用Segment徊哑,就可以進行并發(fā)使用了袜刷。

5鎖升級(無鎖|偏向鎖|輕量級鎖|重量級鎖)

無鎖

無鎖狀態(tài)其實就是上面講的樂觀鎖,這里不再贅述莺丑。
偏向鎖

Java偏向鎖(Biased Locking)是指它會偏向于第一個訪問鎖的線程著蟹,如果在運行過程中,只有一個線程訪問加鎖的資源梢莽,不存在多線程競爭的情況萧豆,那么線程是不需要重復(fù)獲取鎖的,這種情況下昏名,就會給線程加一個偏向鎖炕横。

偏向鎖的實現(xiàn)是通過控制對象Mark Word的標(biāo)志位來實現(xiàn)的,如果當(dāng)前是可偏向狀態(tài)葡粒,需要進一步判斷對象頭存儲的線程 ID 是否與當(dāng)前線程 ID 一致份殿,如果一致直接進入膜钓。
輕量級鎖

當(dāng)線程競爭變得比較激烈時,偏向鎖就會升級為輕量級鎖卿嘲,輕量級鎖認(rèn)為雖然競爭是存在的颂斜,但是理想情況下競爭的程度很低,通過自旋方式等待上一個線程釋放鎖拾枣。
重量級鎖

如果線程并發(fā)進一步加劇沃疮,線程的自旋超過了一定次數(shù),或者一個線程持有鎖梅肤,一個線程在自旋司蔬,又來了第三個線程訪問時(反正就是競爭繼續(xù)加大了),輕量級鎖就會膨脹為重量級鎖姨蝴,重量級鎖會使除了此時擁有鎖的線程以外的線程都阻塞俊啼。

升級到重量級鎖其實就是互斥鎖了,一個線程拿到鎖左医,其余線程都會處于阻塞等待狀態(tài)授帕。

在 Java 中,synchronized 關(guān)鍵字內(nèi)部實現(xiàn)原理就是鎖升級的過程:無鎖 --> 偏向鎖 --> 輕量級鎖 --> 重量級鎖

6 鎖優(yōu)化

鎖粗化, 鎖住的范圍增大,
鎖消除 編譯過程中發(fā)現(xiàn)不需要加鎖的就直接消除同步鎖

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末浮梢,一起剝皮案震驚了整個濱河市跛十,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌秕硝,老刑警劉巖芥映,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異远豺,居然都是意外死亡屏轰,警方通過查閱死者的電腦和手機佑惠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門突梦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人已艰,你說我怎么就攤上這事榛做⊙湔担” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵检眯,是天一觀的道長厘擂。 經(jīng)常有香客問我,道長锰瘸,這世上最難降的妖魔是什么刽严? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮避凝,結(jié)果婚禮上舞萄,老公的妹妹穿的比我還像新娘眨补。我一直安慰自己,他們只是感情好倒脓,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布撑螺。 她就那樣靜靜地躺著,像睡著了一般崎弃。 火紅的嫁衣襯著肌膚如雪甘晤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天饲做,我揣著相機與錄音线婚,去河邊找鬼。 笑死盆均,一個胖子當(dāng)著我的面吹牛塞弊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播缀踪,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼虹脯!你這毒婦竟也來了驴娃?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤循集,失蹤者是張志新(化名)和其女友劉穎唇敞,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體咒彤,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡疆柔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了镶柱。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片旷档。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖歇拆,靈堂內(nèi)的尸體忽然破棺而出鞋屈,到底是詐尸還是另有隱情,我是刑警寧澤故觅,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布厂庇,位于F島的核電站,受9級特大地震影響输吏,放射性物質(zhì)發(fā)生泄漏权旷。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一贯溅、第九天 我趴在偏房一處隱蔽的房頂上張望拄氯。 院中可真熱鬧躲查,春花似錦、人聲如沸坤邪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽艇纺。三九已至怎静,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間黔衡,已是汗流浹背蚓聘。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留盟劫,地道東北人夜牡。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像侣签,于是被迫代替她去往敵國和親塘装。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353

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