java 多線程匿醒,高并發(fā)編程之三 可重入鎖和不可重入鎖

場(chǎng)景:進(jìn)屋排隊(duì)打印東西

可重入鎖:排隊(duì)拿到打印權(quán)(鑰匙)场航,開(kāi)門開(kāi)鎖,打印完畢青抛,關(guān)門旗闽,打算交鑰匙,同學(xué)打電話給來(lái)蜜另,幫他打一份适室,這時(shí)候不用重新排隊(duì),繼續(xù)開(kāi)門再打印一份

不可重入鎖:排隊(duì)拿到打印權(quán)(鑰匙)举瑰,開(kāi)門開(kāi)鎖捣辆,打印完畢,走人此迅,不可再繼續(xù)打第二份汽畴,除非排隊(duì)去

不可重入鎖:

public class Lock {

private boolean isLocked=false;

public? synchronized void lock(){
? ? while(isLocked){

//說(shuō)明已經(jīng)打印過(guò),那么釋放鎖耸序,排隊(duì)去

wait();

? ? ?}

isLocked=true;

System.out.println("打印文件");

}

}

這是想重新打印一份的類?

public class Count{

Lock lock = new Lock();

public void print() throws InterruptedException{

lock.lock();

doAdd();

lock.unlock();

}

public void doAdd() throws InterruptedException{

lock.lock();

System.out.println("又想打印一張");

lock.unlock();

}

public static void main(String[] args) throws InterruptedException {

Count c=new Count();

c.print();

}

}

這時(shí)候會(huì)出現(xiàn)不可重入鎖情況忍些,處于wait狀態(tài),鎖又沒(méi)有釋放坎怪,相當(dāng)于打印完罢坝,叫你去排隊(duì),你帶著鑰匙到后面排隊(duì)了搅窿,所有人都拿不到鑰匙了嘁酿,死鎖

改成可重入鎖:

設(shè)計(jì)思路,判斷是否當(dāng)前的線程男应,即是否同一個(gè)人獲得了打印權(quán)闹司,即拿到了開(kāi)門鑰匙,另外增加計(jì)數(shù)器沐飘,即開(kāi)鎖進(jìn)門和從門內(nèi)出來(lái)次數(shù)的相減值游桩,只有值為0,表示準(zhǔn)備交接下一人

public class Lock{

boolean isLocked = false;

Thread? lockedBy = null;

int lockedCount = 0;

public synchronized void lock()

throws InterruptedException{

Thread thread = Thread.currentThread();

while(isLocked && lockedBy != thread){

wait();

}

isLocked = true;

lockedCount++;

lockedBy = thread;

}

public synchronized void unlock(){

if(Thread.currentThread() == this.lockedBy){

lockedCount--;

if(lockedCount == 0){

isLocked = false;

notify();

}

}

}


另外一個(gè)例子

前言

相信學(xué)過(guò)java的人都知道 synchronized 這個(gè)關(guān)鍵詞薪铜,也知道它用于控制多線程對(duì)并發(fā)資源的安全訪問(wèn)众弓,興許,你還用過(guò)Lock相關(guān)的功能隔箍,但你可能從來(lái)沒(méi)有想過(guò)java中的鎖底層的機(jī)制是怎么實(shí)現(xiàn)的谓娃。如果真是這樣,而且你有興趣了解蜒滩,今天我將帶領(lǐng)你輕松的學(xué)習(xí)下java中非常重要滨达,也非衬坛恚基礎(chǔ)的可重入鎖-ReentrantLock的實(shí)現(xiàn)機(jī)制。

聽(tīng)故事把知識(shí)掌握了

在一個(gè)村子里面捡遍,有一口井水锌订,水質(zhì)非常的好,村民們都想打井里的水画株。這井只有一口辆飘,村里的人那么多,所以得出個(gè)打水的規(guī)則才行谓传。村長(zhǎng)絞盡腦汁蜈项,最終想出了一個(gè)比較合理的方案,咱們來(lái)仔細(xì)的看看聰明的村長(zhǎng)大人的智慧续挟。

井邊安排一個(gè)看井人紧卒,維護(hù)打水的秩序。

打水時(shí)诗祸,以家庭為單位跑芳,哪個(gè)家庭任何人先到井邊,就可以先打水直颅,而且如果一個(gè)家庭占到了打水權(quán)博个,其家人這時(shí)候過(guò)來(lái)打水不用排隊(duì)。而那些沒(méi)有搶占到打水權(quán)的人功偿,一個(gè)一個(gè)挨著在井邊排成一隊(duì)坡倔,先到的排在前面。打水示意圖如下 :

是不是感覺(jué)很和諧脖含,如果打水的人打完了,他會(huì)跟看井人報(bào)告投蝉,看井人會(huì)讓第二個(gè)人接著打水养葵。這樣大家總都能夠打到水。是不是看起來(lái)挺公平的瘩缆,先到的人先打水关拒,當(dāng)然不是絕對(duì)公平的,自己看看下面這個(gè)場(chǎng)景 :

看著庸娱,一個(gè)有娃的父親正在打水着绊,他的娃也到井邊了,所以女憑父貴直接排到最前面打水熟尉,羨煞旁人了归露。

以上這個(gè)故事模型就是所謂的公平鎖模型,當(dāng)一個(gè)人想到井邊打水斤儿,而現(xiàn)在打水的人又不是自家人剧包,這時(shí)候就得乖乖在隊(duì)列后面排隊(duì)恐锦。

事情總不是那么一帆風(fēng)順的,總會(huì)有些人想走捷徑疆液,話說(shuō)看井人年紀(jì)大了一铅,有時(shí)候,眼力不是很好堕油,這時(shí)候潘飘,人們開(kāi)始打起了新主意。新來(lái)打水的人掉缺,他們看到有人排隊(duì)打水的時(shí)候卜录,他們不會(huì)那么乖巧的就排到最后面去排隊(duì),反之攀圈,他們會(huì)看看現(xiàn)在有沒(méi)有人正在打水暴凑,如果有人在打水,沒(méi)輒了赘来,只好排到隊(duì)列最后面现喳,但如果這時(shí)候前面打水的人剛剛打完水,正在交接中犬辰,排在隊(duì)頭的人還沒(méi)有完成交接工作嗦篱,這時(shí)候,新來(lái)的人可以嘗試搶打水權(quán)幌缝,如果搶到了灸促,呵呵,其他人也只能睜一只眼閉一只眼涵卵,因?yàn)榇蠹叶寄J(rèn)這個(gè)規(guī)則了浴栽。這就是所謂的非公平鎖模型。新來(lái)的人不一定總得乖乖排隊(duì)轿偎,這也就造成了原來(lái)隊(duì)列中排隊(duì)的人可能要等很久很久典鸡。

java可重入鎖-ReentrantLock實(shí)現(xiàn)細(xì)節(jié)

ReentrantLock支持兩種獲取鎖的方式,一種是公平模型坏晦,一種是非公平模型萝玷。在繼續(xù)之前,咱們先把故事元素轉(zhuǎn)換為程序元素昆婿。

咱們先來(lái)說(shuō)說(shuō)公平鎖模型:

初始化時(shí)球碉, state=0,表示無(wú)人搶占了打水權(quán)仓蛆。這時(shí)候睁冬,村民A來(lái)打水(A線程請(qǐng)求鎖),占了打水權(quán)看疙,把state+1痴突,如下所示:

線程A取得了鎖搂蜓,把 state原子性+1,這時(shí)候state被改為1,A線程繼續(xù)執(zhí)行其他任務(wù)辽装,然后來(lái)了村民B也想打水(線程B請(qǐng)求鎖)帮碰,線程B無(wú)法獲取鎖,生成節(jié)點(diǎn)進(jìn)行排隊(duì)拾积,如下圖所示:

初始化的時(shí)候殉挽,會(huì)生成一個(gè)空的頭節(jié)點(diǎn),然后才是B線程節(jié)點(diǎn)拓巧,這時(shí)候斯碌,如果線程A又請(qǐng)求鎖,是否需要排隊(duì)肛度?答案當(dāng)然是否定的傻唾,否則就直接死鎖了。當(dāng)A再次請(qǐng)求鎖承耿,就相當(dāng)于是打水期間冠骄,同一家人也來(lái)打水了,是有特權(quán)的加袋,這時(shí)候的狀態(tài)如下圖所示:

到了這里凛辣,相信大家應(yīng)該明白了什么是可重入鎖了吧。就是一個(gè)線程在獲取了鎖之后职烧,再次去獲取了同一個(gè)鎖扁誓,這時(shí)候僅僅是把狀態(tài)值進(jìn)行累加。如果線程A釋放了一次鎖蚀之,就成這樣了:

僅僅是把狀態(tài)值減了蝗敢,只有線程A把此鎖全部釋放了,狀態(tài)值減到0了足删,其他線程才有機(jī)會(huì)獲取鎖前普。當(dāng)A把鎖完全釋放后,state恢復(fù)為0壹堰,然后會(huì)通知隊(duì)列喚醒B線程節(jié)點(diǎn),使B可以再次競(jìng)爭(zhēng)鎖骡湖。當(dāng)然贱纠,如果B線程后面還有C線程,C線程繼續(xù)休眠响蕴,除非B執(zhí)行完了谆焊,通知了C線程。注意浦夷,當(dāng)一個(gè)線程節(jié)點(diǎn)被喚醒然后取得了鎖辖试,對(duì)應(yīng)節(jié)點(diǎn)會(huì)從隊(duì)列中刪除辜王。

非公平鎖模型

如果你已經(jīng)明白了前面講的公平鎖模型,那么非公平鎖模型也就非常容易理解了罐孝。當(dāng)線程A執(zhí)行完之后呐馆,要喚醒線程B是需要時(shí)間的,而且線程B醒來(lái)后還要再次競(jìng)爭(zhēng)鎖莲兢,所以如果在切換過(guò)程當(dāng)中汹来,來(lái)了一個(gè)線程C,那么線程C是有可能獲取到鎖的改艇,如果C獲取到了鎖收班,B就只能繼續(xù)乖乖休眠了。這里就不再畫圖說(shuō)明了谒兄。

其它知識(shí)點(diǎn)

java5中添加了一個(gè)并發(fā)包摔桦, java.util.concurrent,里面提供了各種并發(fā)的工具類承疲,通過(guò)此工具包邻耕,可以在java當(dāng)中實(shí)現(xiàn)功能非常強(qiáng)大的多線程并發(fā)操作。對(duì)于每個(gè)java攻城獅纪隙,我覺(jué)得非常有必要了解這個(gè)包的功能赊豌。雖然做不到一步到位,但慢慢虛心學(xué)習(xí)绵咱,沉下心來(lái)碘饼,總能慢慢領(lǐng)悟到j(luò)ava多線程編程的精華。

結(jié)束語(yǔ)

可重入鎖的實(shí)現(xiàn)會(huì)涉及到CAS悲伶,AQS艾恼,java內(nèi)存可見(jiàn)性(volatile)等知識(shí),為了避免大家直接被代碼搞暈麸锉,故而想以最簡(jiǎn)單的方式把可重入鎖進(jìn)行抽象钠绍,講明白其中的實(shí)現(xiàn)原理,這樣看起源碼也有個(gè)借鑒的思路花沉,希望本篇能夠幫助到你們柳爽。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市碱屁,隨后出現(xiàn)的幾起案子磷脯,更是在濱河造成了極大的恐慌,老刑警劉巖娩脾,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赵誓,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)俩功,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門幻枉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人诡蜓,你說(shuō)我怎么就攤上這事熬甫。” “怎么了万牺?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵罗珍,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我脚粟,道長(zhǎng)覆旱,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任核无,我火速辦了婚禮扣唱,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘团南。我一直安慰自己噪沙,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布吐根。 她就那樣靜靜地躺著正歼,像睡著了一般跛十。 火紅的嫁衣襯著肌膚如雪梆掸。 梳的紋絲不亂的頭發(fā)上淮野,一...
    開(kāi)封第一講書(shū)人閱讀 51,370評(píng)論 1 302
  • 那天琳水,我揣著相機(jī)與錄音,去河邊找鬼撬槽。 笑死损趋,一個(gè)胖子當(dāng)著我的面吹牛崖面,可吹牛的內(nèi)容都是我干的术幔。 我是一名探鬼主播另萤,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼诅挑!你這毒婦竟也來(lái)了四敞?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤拔妥,失蹤者是張志新(化名)和其女友劉穎忿危,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體毒嫡,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了兜畸。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片努释。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖咬摇,靈堂內(nèi)的尸體忽然破棺而出伐蒂,到底是詐尸還是另有隱情,我是刑警寧澤肛鹏,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布逸邦,位于F島的核電站,受9級(jí)特大地震影響在扰,放射性物質(zhì)發(fā)生泄漏缕减。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一芒珠、第九天 我趴在偏房一處隱蔽的房頂上張望桥狡。 院中可真熱鬧,春花似錦皱卓、人聲如沸裹芝。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)嫂易。三九已至,卻和暖如春掐禁,著一層夾襖步出監(jiān)牢的瞬間怜械,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工穆桂, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留宫盔,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓享完,卻偏偏與公主長(zhǎng)得像灼芭,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子般又,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

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