Object类中的两个方法——wait和notify使用总结
?? ?Object類中的wait 、和 notify方法是用來處理線程的方法,既然定義在Object類中,兩個方法的重要程度可見一斑:
兩個方法的使用上都很復(fù)雜:通過閱讀API獲得更多對方法的理解:
The current thread must own this object'smonitor. The thread releases ownership of this monitor and waits until anotherthread notifies threads waiting on this object's monitor to wake up eitherthrough a call to thenotify method or the notifyAll method. The thread then waits until it can re-obtain ownership ofthe monitor and resumes execution
?
?
“當(dāng)前的線程必須要獲得對象的鎖!”
實現(xiàn)這個條件的做法就是wait 方法一定要定義在synchronized方法中或者synchronized代碼塊中;
線程必須要兩次獲得鎖才能完全的執(zhí)行synchronized中的所有內(nèi)容;
當(dāng)?shù)谝淮握{(diào)用到達(dá)wait方法時,The thread realeases ownership of this monitor and waituntil another thread notifies threads waiting on this …
線程會暫時釋放鎖的擁有權(quán),等待其他線程的notify方法或者notifyAll方法喚醒該線程,繼續(xù)執(zhí)行代碼!
?
?
?
30.
下面一個程序要求定義兩個線程類,一個實現(xiàn)將目標(biāo)加一,一個實現(xiàn)將目標(biāo)減一,目標(biāo)初始值為零,要求加一減一交替進(jìn)行;
顯然的單純調(diào)用synchronized是無法滿足條件的,需要使用wait,和notify方法;
?
package thread;
?
publicclass ThreadTest
{
?
?? publicstaticvoid main(String[] args)
?? {
????? ThreadDemo2 demo = new ThreadDemo2();
????? ThreadIncrease test1 = new ThreadIncrease(demo);
????? ThreadDecrease test2 = new ThreadDecrease(demo);
????? test1.start();
????? test2.start();
?? }
}
class ThreadDemo2
{
?? privateintnum = 0;
?? publicsynchronizedvoid Increase()
?? {
????? /*
????? ?* 下面的代碼是核心代碼
????? ?* 什么時候要讓線程等待,當(dāng)然是不符合條件的時候
????? ?* 目的是想讓num = 0 的時候才執(zhí)行加一的操作,當(dāng)num不等于零的時候會執(zhí)行wait等待通知
????? ?* 當(dāng)通知num已經(jīng)變?yōu)?/span>0時,wait結(jié)束,執(zhí)行下面語句num++;
????? ?* 然后執(zhí)行notify方法!
????? ?* 當(dāng)然的一說Java中的synchronized總是伴隨著wait和notify方法共同的存在;
????? ?*/
?????
????? if(num != 0)
????? {
??????? try
??????? {
?????????? wait();
??????? }
??????? catch (InterruptedException e)
??????? {
?????????? // TODO Auto-generatedcatch block
?????????? e.printStackTrace();
??????? }
????? }
????? num ++;
????? System.out.println(num);
????? notify();
????? }
??
?? publicsynchronizedvoid decrease()
?? {
?????
????? if(num == 0)
????? {
??????? try
??????? {
?????????? wait();
??????? }
??????? catch (InterruptedException e)
??????? {
?????????? // TODO Auto-generatedcatch block
?????????? e.printStackTrace();
??????? }
????? }
????? num --;
????? System.out.println(num);
?????
????? notify();
????? }
?????
??
}
class ThreadIncreaseextends Thread
{
?? private ThreadDemo2demo;
?? public ThreadIncrease(ThreadDemo2 demo)
?? {
????? this.demo = demo;
?? }
?? @Override
?? publicvoid run()
?? {
????? for(int i = 0 ; i < 15; i ++)
????? {
????? demo.Increase();
????? }
?? }
??
}
class ThreadDecreaseextends Thread
{
?? private ThreadDemo2demo;
?? public ThreadDecrease(ThreadDemo2 demo)
?? {
????? this.demo = demo;
?????
?? }
?? @Override
?? publicvoid run()
?? {
????? for(int i = 0 ; i < 15; i ++)
????? {
????? demo.decrease();
????? }
?? }
}
?
?
?
31.
可惜的是上面的代碼仍然有著致命的弱點,線程并不僅僅有兩個,而且是兩個相對的線程!
致命的弱點在于: 當(dāng)線程在wait的時候它并不知道其他的線程到底做了什么!
現(xiàn)在我們將增加一個Increase線程類,和一個Decrease線程類
,并且調(diào)用它們的start方法運行后,你將看到這樣的結(jié)果:
我們足以看到代碼的脆弱性,為什么會出現(xiàn)這種情況,更糟糕的是結(jié)果是隨機(jī)的!上面已經(jīng)說得很清楚了:當(dāng)線程在wait的時候,它不知道其他的線程正在做什么,
所以需要將代碼變得更加健壯:
我們舉一個為什么會出現(xiàn)這種情況的原因之一:
我們假設(shè)線程1、2調(diào)用增加方法,線程3、4調(diào)用減少方法
假設(shè)線程3 先訪問了減少方法,因為此時num的值為0,所以wait,并且交出ownership,假設(shè)線程4又訪問了減少方法,同樣的wait,并且交出所有權(quán),再假設(shè)線程1訪問了增加方法,將num的值變?yōu)?,并且調(diào)用notify方法,假設(shè)notify了線程3,線程3將num的值變?yōu)?;并且notify,如果此時notify了線程4,那么悲劇就會發(fā)生了,線程4醒來后,會繼續(xù)將num減一,變?yōu)?1,一步錯,后面就全錯了;
缺點就在于notify的隨機(jī)性,所以在某個wait方法被喚醒時,增加判斷條件,如果不符合條件,繼續(xù)wait,顯然 while循環(huán)是最合適的
!
全部的變化只需要將 if 改為 while!!
由于num是成員變量被線程共享,每當(dāng)wait被喚醒,都會判斷一次;
package thread;
?
publicclass ThreadTest
{
?
?? publicstaticvoid main(String[] args)
?? {
????? ThreadDemo2 demo = new ThreadDemo2();
????? ThreadIncrease test1 = new ThreadIncrease(demo);
????? ThreadDecrease test2 = new ThreadDecrease(demo);
????? ThreadIncrease test3 = new ThreadIncrease(demo);
????? ThreadDecrease test4 = new ThreadDecrease(demo);
????? test1.start();
????? test2.start();
????? test3.start();
????? test4.start();
?? }
}
class ThreadDemo2
{
?? privateintnum = 0;
?? publicsynchronizedvoid Increase()
?? {
????? /*
????? ?* 下面的代碼是核心代碼
????? ?* 什么時候要讓線程等待,當(dāng)然是不符合條件的時候
????? ?* 目的是想讓num = 0 的時候才執(zhí)行加一的操作,當(dāng)num不等于零的時候會執(zhí)行wait等待通知
????? ?* 當(dāng)通知num已經(jīng)變?yōu)?/span>0時,wait結(jié)束,執(zhí)行下面語句num++;
????? ?* 然后執(zhí)行notify方法!
????? ?* 當(dāng)然的一說Java中的synchronized總是伴隨著wait和notify方法共同的存在;
????? ?*/
?????
?? ?? while(num != 0)
????? {
??????? try
??????? {
?????????? wait();
??????? }
??????? catch (InterruptedException e)
??????? {
?????????? // TODO Auto-generatedcatch block
?????????? e.printStackTrace();
??????? }
????? }
????? num ++;
????? System.out.println(num);
????? notify();
????? }
??
?? publicsynchronizedvoid decrease()
?? {
?????
????? while(num == 0)
????? {
??????? try
??????? {
?????????? wait();
??????? }
??????? catch (InterruptedException e)
??????? {
?????????? // TODO Auto-generatedcatch block
?????????? e.printStackTrace();
??????? }
????? }
????? num --;
????? System.out.println(num);
?????
????? notify();
????? }
?????
??
}
class ThreadIncreaseextends Thread
{
?? private ThreadDemo2demo;
?? public ThreadIncrease(ThreadDemo2 demo)
?? {
????? this.demo = demo;
?? }
?? @Override
?? publicvoid run()
?? {
????? for(int i = 0 ; i < 15; i ++)
????? {
??????? try
??????? {
?????????? Thread.sleep((long)(Math.random()*1000));
??????? }
??????? catch (InterruptedException e)
??????? {
?????????? // TODO Auto-generatedcatch block
?????????? e.printStackTrace();
??????? }
??????? demo.Increase();
????? }
?? }
??
}
class ThreadDecreaseextends Thread
{
?? private ThreadDemo2demo;
?? public ThreadDecrease(ThreadDemo2 demo)
?? {
????? this.demo = demo;
?????
?? }
?? @Override
?? publicvoid run()
?? {
????? for(int i = 0 ; i < 15; i ++)
????? {
??????? try
??????? {
?????????? Thread.sleep((long)(Math.random()*1000));
??????? }
??????? catch (InterruptedException e)
??????? {
?????????? // TODO Auto-generatedcatch block
?????????? e.printStackTrace();
??????? }
??????? demo.decrease();
????? }
?? }
}
總結(jié)
以上是生活随笔為你收集整理的Object类中的两个方法——wait和notify使用总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 你用或者不用:线程中synchroniz
- 下一篇: 浅谈装饰模式应用于IO中