摘要:必須放在中,否則會(huì)在時(shí)扔出異常。為了控制線程執(zhí)行的順序,那么就必須要確定喚醒等待的順序,所以每一個(gè)線程必須同時(shí)持有兩個(gè)對(duì)象鎖,才能繼續(xù)執(zhí)行。一個(gè)對(duì)象鎖是,就是前一個(gè)線程所持有的對(duì)象鎖。
簡(jiǎn)單介紹
wait()方法是Object類里的方法;當(dāng)一個(gè)線程執(zhí)行到wait()方法時(shí),它就進(jìn)入到一個(gè)和該對(duì)象相關(guān)的等待池中,同時(shí)失去(釋放)了對(duì)象的機(jī)鎖(暫時(shí)失去機(jī)鎖,wait(long timeout)超時(shí)時(shí)間到后還需要返還對(duì)象鎖);其他線程可以訪問(wèn);wait()使用notify或者notifyAlll或者指定睡眠時(shí)間來(lái)喚醒當(dāng)前等待池中的線程。wiat()必須放在synchronized block中,否則會(huì)在program runtime時(shí)扔 出“java.lang.IllegalMonitorStateException”異常。 簡(jiǎn)單的介紹就到這里,現(xiàn)在我們用一個(gè)例子來(lái)深入理解一下
package com.example.demo.test.MultithreadingTest; public class MyThreadPrinter2 implements Runnable { private String name; private Object prev; private Object self; private MyThreadPrinter2(String name, Object prev, Object self) { this.name = name; this.prev = prev; this.self = self; } @Override public void run() { int count = 10; int x=0; while (count > 0) { synchronized (prev) { synchronized (self) { System.out.print(name); count--; x++; self.notify(); } try { prev.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } synchronized (prev){ System.out.print(x); } } } public static void main(String[] args) throws Exception { Object a = new Object(); Object b = new Object(); Object c = new Object(); MyThreadPrinter2 pa = new MyThreadPrinter2("A", c, a); MyThreadPrinter2 pb = new MyThreadPrinter2("B", a, b); MyThreadPrinter2 pc = new MyThreadPrinter2("C", b, c); new Thread(pa).start(); Thread.sleep(100); new Thread(pb).start(); Thread.sleep(100); new Thread(pc).start(); Thread.sleep(100); } }
輸出結(jié)果:
ABC1A1B1C2A2B2C3A3B3C4A4B4C5A5B5C6A6B6C7A7B7C8A8B8C9A9B9C10
這段代碼為三線程間的同步喚醒操作,主要的目的就是ThreadA->ThreadB->ThreadC->ThreadA循環(huán)執(zhí)行三個(gè)線程。
為了控制線程執(zhí)行的順序,那么就必須要確定喚醒、等待的順序,所以每一個(gè)線程必須同時(shí)持有兩個(gè)對(duì)象鎖,才能繼續(xù)執(zhí)行。一個(gè)對(duì)象鎖是prev,就是前一個(gè)線程所持有的對(duì)象鎖。還有一個(gè)就是自身對(duì)象鎖。主要的思想就是,為了控制執(zhí)行的順序,必須要先持有prev鎖,也就前一個(gè)線程要釋放自身對(duì)象鎖,再去申請(qǐng)自身對(duì)象鎖,兩者兼?zhèn)鋾r(shí)打印,之后首先調(diào)用self.notify()釋放自身對(duì)象鎖,喚醒下一個(gè)等待線程,再調(diào)用prev.wait()釋放prev對(duì)象鎖,終止當(dāng)前線程,等待循環(huán)結(jié)束后再次被喚醒。prev.wait()之后,加入了一個(gè)對(duì)象鎖是prev的輸出x,用來(lái)展示什么時(shí)候釋放了prev對(duì)象鎖。
運(yùn)行上述代碼,可以發(fā)現(xiàn)先打印出A,再釋放A,然后C鎖,進(jìn)入ThreadB,打印出B,再釋放B,然后A鎖,進(jìn)入ThreadC,打印出C,再釋放C,然后B鎖,此時(shí)會(huì)進(jìn)入ThreadA,繼續(xù)執(zhí)行開始時(shí)wait的線程,輸出x,打印出A,再釋放A,然后C鎖......如此循環(huán)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/71618.html
摘要:和簡(jiǎn)介和均為的方法暫停一個(gè)線程喚醒一個(gè)線程從以上的定義中,我們可以了解到以下事實(shí)想要使用這兩個(gè)方法,我們需要先有一個(gè)對(duì)象。在中任何一個(gè)時(shí)刻,對(duì)象的控制權(quán)只能被一個(gè)線程擁有。若有多個(gè)線程處于此控制權(quán)下的狀態(tài),只有一個(gè)會(huì)被喚醒。 最近看帖子,發(fā)現(xiàn)一道面試題: 啟動(dòng)兩個(gè)線程, 一個(gè)輸出 1,3,5,7…99, 另一個(gè)輸出 2,4,6,8…100 最后 STDOUT 中按序輸出 1,2,3,4...
摘要:無(wú)論在中出現(xiàn)什么,都可以認(rèn)為它是對(duì)象除了八大基本數(shù)據(jù)類型。讓當(dāng)前線程等待某個(gè)對(duì)象的鎖,當(dāng)然應(yīng)該通過(guò)這個(gè)對(duì)象來(lái)操作了。但是要注意的是方法調(diào)用后,被喚醒的線程不會(huì)立馬獲得到鎖對(duì)象。主要的區(qū)別在于在釋放同時(shí),釋放了對(duì)象鎖的控制。 前言 五一回家又?jǐn)喔艘粋€(gè)放假時(shí)間了~~~ 只有光頭才能變強(qiáng) 回顧前面: ThreadLocal就是這么簡(jiǎn)單 多線程三分鐘就可以入個(gè)門了! 多線程基礎(chǔ)必要知識(shí)點(diǎn)!...
摘要:方法可以將當(dāng)前線程放入等待集合中,并釋放當(dāng)前線程持有的鎖。此后,該線程不會(huì)接收到的調(diào)度,并進(jìn)入休眠狀態(tài)。該線程會(huì)喚醒,并嘗試恢復(fù)之前的狀態(tài)。 并發(fā) 最近重新復(fù)習(xí)了一邊并發(fā)的知識(shí),發(fā)現(xiàn)自己之前對(duì)于并發(fā)的了解只是皮毛。這里總結(jié)以下Java并發(fā)需要掌握的點(diǎn)。 使用并發(fā)的一個(gè)重要原因是提高執(zhí)行效率。由于I/O等情況阻塞,單個(gè)任務(wù)并不能充分利用CPU時(shí)間。所以在單處理器的機(jī)器上也應(yīng)該使用并發(fā)。為...
摘要:運(yùn)行可運(yùn)行狀態(tài)的線程獲得了時(shí)間片,執(zhí)行程序代碼。阻塞的情況分三種一等待阻塞運(yùn)行的線程執(zhí)行方法,會(huì)把該線程放入等待隊(duì)列中。死亡線程方法執(zhí)行結(jié)束,或者因異常退出了方法,則該線程結(jié)束生命周期。死亡的線程不可再次復(fù)生。 系列文章傳送門: Java多線程學(xué)習(xí)(一)Java多線程入門 Java多線程學(xué)習(xí)(二)synchronized關(guān)鍵字(1) java多線程學(xué)習(xí)(二)synchronized關(guān)鍵...
閱讀 2906·2021-11-15 11:39
閱讀 1528·2021-08-19 10:56
閱讀 1100·2019-08-30 14:12
閱讀 3748·2019-08-29 17:29
閱讀 725·2019-08-29 16:21
閱讀 3427·2019-08-26 12:22
閱讀 1522·2019-08-23 16:30
閱讀 1029·2019-08-23 15:25