Java多線程學(xué)習(xí)之wait、notify/notifyAll 詳解
1、wait()、notify/notifyAll() 方法是Object的本地final方法,無(wú)法被重寫(xiě)。
2、wait()使當(dāng)前線程阻塞,前提是 必須先獲得鎖,一般配合synchronized 關(guān)鍵字使用,即,一般在synchronized 同步代碼塊里使用 wait()、notify/notifyAll() 方法。
3、 由于 wait()、notify/notifyAll() 在synchronized 代碼塊執(zhí)行,說(shuō)明當(dāng)前線程一定是獲取了鎖的。
當(dāng)線程執(zhí)行wait()方法時(shí)候,會(huì)釋放當(dāng)前的鎖,然后讓出CPU,進(jìn)入等待狀態(tài)。
只有當(dāng) notify/notifyAll() 被執(zhí)行時(shí)候,才會(huì)喚醒一個(gè)或多個(gè)正處于等待狀態(tài)的線程,然后繼續(xù)往下執(zhí)行,直到執(zhí)行完synchronized 代碼塊的代碼或是中途遇到wait() ,再次釋放鎖。
也就是說(shuō),notify/notifyAll() 的執(zhí)行只是喚醒沉睡的線程,而不會(huì)立即釋放鎖,鎖的釋放要看代碼塊的具體執(zhí)行情況。所以在編程中,盡量在使用了notify/notifyAll() 后立即退出臨界區(qū),以喚醒其他線程讓其獲得鎖。
4、wait() 需要被try catch包圍,以便發(fā)生異常中斷也可以使wait等待的線程喚醒。
5、notify 和wait 的順序不能錯(cuò),如果A線程先執(zhí)行notify方法,B線程在執(zhí)行wait方法,那么B線程是無(wú)法被喚醒的。
6、notify 和 notifyAll的區(qū)別
notify方法只喚醒一個(gè)等待(對(duì)象的)線程并使該線程開(kāi)始執(zhí)行。所以如果有多個(gè)線程等待一個(gè)對(duì)象,這個(gè)方法只會(huì)喚醒其中一個(gè)線程,選擇哪個(gè)線程取決于操作系統(tǒng)對(duì)多線程管理的實(shí)現(xiàn)。notifyAll 會(huì)喚醒所有等待(對(duì)象的)線程,盡管哪一個(gè)線程將會(huì)第一個(gè)處理取決于操作系統(tǒng)的實(shí)現(xiàn)。如果當(dāng)前情況下有多個(gè)線程需要被喚醒,推薦使用notifyAll 方法。比如在生產(chǎn)者-消費(fèi)者里面的使用,每次都需要喚醒所有的消費(fèi)者或是生產(chǎn)者,以判斷程序是否可以繼續(xù)往下執(zhí)行。
7、在多線程中要測(cè)試某個(gè)條件的變化,使用if 還是while?
要注意,notify喚醒沉睡的線程后,線程會(huì)接著上次的執(zhí)行繼續(xù)往下執(zhí)行。所以在進(jìn)行條件判斷時(shí)候,可以先把 wait 語(yǔ)句忽略不計(jì)來(lái)進(jìn)行考慮;顯然,要確保程序一定要執(zhí)行,并且要保證程序直到滿足一定的條件再執(zhí)行,要使用while進(jìn)行等待,直到滿足條件才繼續(xù)往下執(zhí)行。如下代碼:
public?class?K?{
????//狀態(tài)鎖
????private?Object lock;
????//條件變量
????private?int?now,need;
????public?void?produce(int?num){
????????//同步
????????synchronized (lock){
???????????//當(dāng)前有的不滿足需要,進(jìn)行等待,直到滿足條件
????????????while(now < need){
????????????????try?{
????????????????????//等待阻塞
????????????????????lock.wait();
????????????????} catch?(InterruptedException e) {
????????????????????e.printStackTrace();
????????????????}
??????????????System.out.println("我被喚醒了!");
????????????}
???????????// 做其他的事情
????????}
????}
}顯然,只有當(dāng)前值滿足需要值的時(shí)候,線程才可以往下執(zhí)行,所以,必須使用while 循環(huán)阻塞。注意,wait() 當(dāng)被喚醒時(shí)候,只是讓while循環(huán)繼續(xù)往下走.如果此處用if的話,意味著if繼續(xù)往下走,會(huì)跳出if語(yǔ)句塊。
8、實(shí)現(xiàn)生產(chǎn)者和消費(fèi)者問(wèn)題?
什么是生產(chǎn)者-消費(fèi)者問(wèn)題呢?

如上圖,假設(shè)有一個(gè)公共的容量有限的池子,有兩種人,一種是生產(chǎn)者,另一種是消費(fèi)者。需要滿足如下條件:
1、生產(chǎn)者產(chǎn)生資源往池子里添加,前提是池子沒(méi)有滿,如果池子滿了,則生產(chǎn)者暫停生產(chǎn),直到自己的生成能放下池子。
2、消費(fèi)者消耗池子里的資源,前提是池子的資源不為空,否則消費(fèi)者暫停消耗,進(jìn)入等待直到池子里有資源數(shù)滿足自己的需求。
- 倉(cāng)庫(kù)類
/**
?* 生產(chǎn)者和消費(fèi)者的問(wèn)題
?* wait、notify/notifyAll() 實(shí)現(xiàn)
?*/
public?class?Storage1?implements?AbstractStorage?{
????//倉(cāng)庫(kù)最大容量
????private?final int?MAX_SIZE = 100;
????//倉(cāng)庫(kù)存儲(chǔ)的載體
????private?LinkedList list?= new?LinkedList();
????//生產(chǎn)產(chǎn)品
????public?void?produce(int?num){
????????//同步
????????synchronized (list){
????????????//倉(cāng)庫(kù)剩余的容量不足以存放即將要生產(chǎn)的數(shù)量,暫停生產(chǎn)
????????????while(list.size()+num > MAX_SIZE){
????????????????System.out.println("【要生產(chǎn)的產(chǎn)品數(shù)量】:"?+ num + "\t【庫(kù)存量】:"
????????????????????????+ list.size() + "\t暫時(shí)不能執(zhí)行生產(chǎn)任務(wù)!");
????????????????try?{
????????????????????//條件不滿足,生產(chǎn)阻塞
????????????????????list.wait();
????????????????} catch?(InterruptedException e) {
????????????????????e.printStackTrace();
????????????????}
????????????}
????????????for(int?i=0;i????????????????list.add(new?Object());
????????????}
????????????System.out.println("【已經(jīng)生產(chǎn)產(chǎn)品數(shù)】:"?+ num + "\t【現(xiàn)倉(cāng)儲(chǔ)量為】:"?+ list.size());
????????????list.notifyAll();
????????}
????}
????//消費(fèi)產(chǎn)品
????public?void?consume(int?num){
????????synchronized (list){
????????????//不滿足消費(fèi)條件
????????????while(num > list.size()){
????????????????System.out.println("【要消費(fèi)的產(chǎn)品數(shù)量】:"?+ num + "\t【庫(kù)存量】:"
????????????????????????+ list.size() + "\t暫時(shí)不能執(zhí)行生產(chǎn)任務(wù)!");
????????????????try?{
????????????????????list.wait();
????????????????} catch?(InterruptedException e) {
????????????????????e.printStackTrace();
????????????????}
????????????}
????????????//消費(fèi)條件滿足,開(kāi)始消費(fèi)
????????????for(int?i=0;i????????????????list.remove();
????????????}
????????????System.out.println("【已經(jīng)消費(fèi)產(chǎn)品數(shù)】:"?+ num + "\t【現(xiàn)倉(cāng)儲(chǔ)量為】:"?+ list.size());
????????????list.notifyAll();
????????}
????}
} - 抽象倉(cāng)庫(kù)類
public?interface?AbstractStorage?{
????void?consume(int?num);
????void?produce(int?num);
}- 生產(chǎn)者
public?class?Producer?extends?Thread{
????//每次生產(chǎn)的數(shù)量
????private?int?num ;
????//所屬的倉(cāng)庫(kù)
????public?AbstractStorage abstractStorage;
????public?Producer(AbstractStorage abstractStorage){
????????this.abstractStorage = abstractStorage;
????}
????public?void?setNum(int?num){
????????this.num = num;
????}
????// 線程run函數(shù)
????@Override
????public?void?run()
????{
????????produce(num);
????}
????// 調(diào)用倉(cāng)庫(kù)Storage的生產(chǎn)函數(shù)
????public?void?produce(int?num)
????{
????????abstractStorage.produce(num);
????}
}- 消費(fèi)者
public?class?Consumer?extends?Thread{
????// 每次消費(fèi)的產(chǎn)品數(shù)量
????private?int?num;
????// 所在放置的倉(cāng)庫(kù)
????private?AbstractStorage abstractStorage1;
????// 構(gòu)造函數(shù),設(shè)置倉(cāng)庫(kù)
????public?Consumer(AbstractStorage abstractStorage1)
????{
????????this.abstractStorage1 = abstractStorage1;
????}
????// 線程run函數(shù)
????public?void?run()
????{
????????consume(num);
????}
????// 調(diào)用倉(cāng)庫(kù)Storage的生產(chǎn)函數(shù)
????public?void?consume(int?num)
????{
????????abstractStorage1.consume(num);
????}
????public?void?setNum(int?num){
????????this.num = num;
????}
}- 測(cè)試
public?class?Test{
????public?static?void?main(String[] args)?{
????????// 倉(cāng)庫(kù)對(duì)象
????????AbstractStorage abstractStorage = new?Storage1();
????????// 生產(chǎn)者對(duì)象
????????Producer p1 = new?Producer(abstractStorage);
????????Producer p2 = new?Producer(abstractStorage);
????????Producer p3 = new?Producer(abstractStorage);
????????Producer p4 = new?Producer(abstractStorage);
????????Producer p5 = new?Producer(abstractStorage);
????????Producer p6 = new?Producer(abstractStorage);
????????Producer p7 = new?Producer(abstractStorage);
????????// 消費(fèi)者對(duì)象
????????Consumer c1 = new?Consumer(abstractStorage);
????????Consumer c2 = new?Consumer(abstractStorage);
????????Consumer c3 = new?Consumer(abstractStorage);
????????// 設(shè)置生產(chǎn)者產(chǎn)品生產(chǎn)數(shù)量
????????p1.setNum(10);
????????p2.setNum(10);
????????p3.setNum(10);
????????p4.setNum(10);
????????p5.setNum(10);
????????p6.setNum(10);
????????p7.setNum(80);
????????// 設(shè)置消費(fèi)者產(chǎn)品消費(fèi)數(shù)量
????????c1.setNum(50);
????????c2.setNum(20);
????????c3.setNum(30);
????????// 線程開(kāi)始執(zhí)行
????????c1.start();
????????c2.start();
????????c3.start();
????????p1.start();
????????p2.start();
????????p3.start();
????????p4.start();
????????p5.start();
????????p6.start();
????????p7.start();
????}
}- 輸出
【要消費(fèi)的產(chǎn)品數(shù)量】:50????【庫(kù)存量】:0????暫時(shí)不能執(zhí)行生產(chǎn)任務(wù)!
【要消費(fèi)的產(chǎn)品數(shù)量】:20????【庫(kù)存量】:0????暫時(shí)不能執(zhí)行生產(chǎn)任務(wù)!
【要消費(fèi)的產(chǎn)品數(shù)量】:30????【庫(kù)存量】:0????暫時(shí)不能執(zhí)行生產(chǎn)任務(wù)!
【已經(jīng)生產(chǎn)產(chǎn)品數(shù)】:10????【現(xiàn)倉(cāng)儲(chǔ)量為】:10
【要消費(fèi)的產(chǎn)品數(shù)量】:30????【庫(kù)存量】:10????暫時(shí)不能執(zhí)行生產(chǎn)任務(wù)!
【要消費(fèi)的產(chǎn)品數(shù)量】:20????【庫(kù)存量】:10????暫時(shí)不能執(zhí)行生產(chǎn)任務(wù)!
【要消費(fèi)的產(chǎn)品數(shù)量】:50????【庫(kù)存量】:10????暫時(shí)不能執(zhí)行生產(chǎn)任務(wù)!
【已經(jīng)生產(chǎn)產(chǎn)品數(shù)】:10????【現(xiàn)倉(cāng)儲(chǔ)量為】:20
【已經(jīng)生產(chǎn)產(chǎn)品數(shù)】:10????【現(xiàn)倉(cāng)儲(chǔ)量為】:30
【要消費(fèi)的產(chǎn)品數(shù)量】:50????【庫(kù)存量】:30????暫時(shí)不能執(zhí)行生產(chǎn)任務(wù)!
【已經(jīng)消費(fèi)產(chǎn)品數(shù)】:20????【現(xiàn)倉(cāng)儲(chǔ)量為】:10
【要消費(fèi)的產(chǎn)品數(shù)量】:30????【庫(kù)存量】:10????暫時(shí)不能執(zhí)行生產(chǎn)任務(wù)!
【已經(jīng)生產(chǎn)產(chǎn)品數(shù)】:10????【現(xiàn)倉(cāng)儲(chǔ)量為】:20
【要消費(fèi)的產(chǎn)品數(shù)量】:50????【庫(kù)存量】:20????暫時(shí)不能執(zhí)行生產(chǎn)任務(wù)!
【要消費(fèi)的產(chǎn)品數(shù)量】:30????【庫(kù)存量】:20????暫時(shí)不能執(zhí)行生產(chǎn)任務(wù)!
【已經(jīng)生產(chǎn)產(chǎn)品數(shù)】:10????【現(xiàn)倉(cāng)儲(chǔ)量為】:30
【已經(jīng)消費(fèi)產(chǎn)品數(shù)】:30????【現(xiàn)倉(cāng)儲(chǔ)量為】:0
【要消費(fèi)的產(chǎn)品數(shù)量】:50????【庫(kù)存量】:0????暫時(shí)不能執(zhí)行生產(chǎn)任務(wù)!
【已經(jīng)生產(chǎn)產(chǎn)品數(shù)】:10????【現(xiàn)倉(cāng)儲(chǔ)量為】:10
【要消費(fèi)的產(chǎn)品數(shù)量】:50????【庫(kù)存量】:10????暫時(shí)不能執(zhí)行生產(chǎn)任務(wù)!
【已經(jīng)生產(chǎn)產(chǎn)品數(shù)】:80????【現(xiàn)倉(cāng)儲(chǔ)量為】:90
【已經(jīng)消費(fèi)產(chǎn)品數(shù)】:50????【現(xiàn)倉(cāng)儲(chǔ)量為】:40來(lái)源:cnblogs.com/moongeek/p/7631447.html
