小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Object類wait,notify,notifyAll的使用

 9loong 2012-10-10

這三個方法是java的基礎(chǔ)類Object中定義的。

Java所有的類都具有線程的潛力,Java賦予的每個對象一個鎖,在計算機(jī)內(nèi)部工作在同一時間,只有一個對象可以持有鎖,也就是說程序在同一時間只有一個程序可以運(yùn)行,這里我把對象比作是一個小的程序。而多處理器,那么就另當(dāng)別論了。

在這里我們首先學(xué)習(xí)一下公共方法wait,notify,notifyAll。

wait方法可以使在當(dāng)前線程的對象等待,直到別的線程調(diào)用此對象的notify或notifyAll方法(注意:調(diào)用的是此對象的notify和notifyAll),并且當(dāng)前運(yùn)行的線程必須具有此對象的對象監(jiān)視器,對象監(jiān)視器我們可以從三個方法中獲得,如下:

1.在執(zhí)行對象實(shí)例同步方法體中,可以獲得此對象的對象監(jiān)視器,例子偽代碼如下:

synchronized void aMethod(){

while(condition)

this.wait();

//other mothed;
}

2.通過執(zhí)行對象同步synchronized正文,例子偽代碼如下:

synchronized(this){

while(condition)

this.wait();

//other mothed;
}

3.對于 Class 類型的對象,可以通過執(zhí)行該類的同步靜態(tài)方法

這 個方法可以使當(dāng)前對象滿足條件condition后,執(zhí)行等待,當(dāng)前線程對象放棄鎖,cpu記錄當(dāng)前線程狀態(tài),以備下次回復(fù)。然后讓其他線程運(yùn)行,直到其 他線程調(diào)用此對象的notify或notifyAll方法,此對象才會重新獲得此對象的對象監(jiān)視器,此對象才能重新運(yùn)行。

注意:調(diào)用這個方法,必須具有對象監(jiān)視器,也就是說我們必須在這三種方法選一種來獲得對象監(jiān)視器,如果調(diào)用此方法wait,卻沒用對象監(jiān)視器,那么運(yùn)行時會拋出IllegalMonitorStateException.

而且,在靜態(tài)方法中也無法獲得對象監(jiān)視器,只能在Class類型的對象中,我們才可以通過調(diào)用該類的同步靜態(tài)方法來獲得對象監(jiān)視器。

wait()
JDk文檔寫道

在其他線程調(diào)用此對象的 notify() 方法或 notifyAll() 方法前,導(dǎo)致當(dāng)前線程等待。換句話說,此方法的行為就好像它僅執(zhí)行 wait(0) 調(diào)用一樣。
當(dāng)前線程必須擁有此對象監(jiān)視器 。該線程發(fā)布對此監(jiān)視器的所有權(quán)并等待,直到其他線程通過調(diào)用 notify 方法,或 notifyAll 方法通知在此對象的監(jiān)視器上等待的線程醒來。然后該線程將等到重新獲得對監(jiān)視器的所有權(quán)后才能繼續(xù)執(zhí)行。

對于某一個參數(shù)的版本,實(shí)現(xiàn)中斷和虛假喚醒是可能的,而且此方法應(yīng)始終在循環(huán)中使用:

synchronized (obj) {
while (<condition does not hold>)
obj.wait();
... // Perform action appropriate to condition
}

此方法只應(yīng)由作為此對象監(jiān)視器的所有者的線程來調(diào)用。

拋出:
IllegalMonitorStateException - 如果當(dāng)前線程不是此對象監(jiān)視器的所有者。
InterruptedException - 如果在當(dāng)前線程等待通知之前或者正在等待通知時,任何線程中斷了當(dāng)前線程。在拋出此異常時,當(dāng)前線程的中斷狀態(tài) 被清除。
對于紅色部分的內(nèi)容,個人曾一直都不是很理解,什么叫做擁有此對象的監(jiān)視器。下面我們看看代碼: 

 DateFormat format = new SimpleDateFormat("yyyy-MM-dd:hh:mm:ss");
private String getTime(){
    return format.format(Calendar.getInstance().getTime());
}
private Object monitor = new Object();
    public void waitOnce(String thread, final long ms) {
    Thread waitThread = new Thread() {
        public void run() {
            synchronized (monitor) {//獲得對象監(jiān)視器
                try {
                    System.out.println("Thread "
                            + Thread.currentThread().getName()
                            + " Wait at " + getTime());
                    monitor.wait(ms);
                    System.out.println("Thread "
                            + Thread.currentThread().getName()
                            + " Waked at " + getTime());
                } catch (InterruptedException e) {
                }
            }
        };
    };
    waitThread.setName(thread);
    waitThread.start();
}

如果我們?nèi)サ魋ynchronized(monitor) ,運(yùn)行則會出現(xiàn)異常IllegalMonitorStateException。

WaitAndNotifyTest test = new WaitAndNotifyTest();
test.waitOnce("1", Long.MAX_VALUE); 

寫道

Exception in thread “1″ java.lang.IllegalMonitorStateException

而加上以后就沒問題了。因此個人覺得使用synchronized關(guān)鍵字鎖定對象,也就是獲得了對象的監(jiān)視器了。

notify()
JDK文檔 寫道

喚醒在此對象監(jiān)視器上等待的單個線程。如果所有線程都在此對象上等待,則會選擇喚醒其中一個線程 。選擇是任意性 的,并在對實(shí)現(xiàn)做出決定時發(fā)生。線程通過調(diào)用其中一個 wait 方法,在對象的監(jiān)視器上等待。

直到當(dāng)前線程放棄此對象上的鎖定,才能繼續(xù)執(zhí)行被喚醒的線程 。被喚醒的線程將以常規(guī)方式與在該對象上主動同步的其他所有線程進(jìn)行競爭;例如,喚醒的線程在作為鎖定此對象的下一個線程方面沒有可靠的特權(quán)或劣勢。

此方法只應(yīng)由作為此對象監(jiān)視器的所有者的線程來調(diào)用。通過以下三種方法之一,線程可以成為此對象監(jiān)視器的所有者:

通過執(zhí)行此對象的同步實(shí)例方法。
通過執(zhí)行在此對象上進(jìn)行同步的 synchronized 語句的正文。
對于 Class 類型的對象,可以通過執(zhí)行該類的同步靜態(tài)方法。


一次只能有一個線程擁有對象的監(jiān)視器。

拋出:
IllegalMonitorStateException – 如果當(dāng)前線程不是此對象監(jiān)視器的所有者。

首先理解一下獲得對象的監(jiān)視器,簡單的說就是取得了當(dāng)前對象的“加鎖”使用權(quán),最簡單的就是使用synchronized關(guān)鍵字。另外使用 synchronized修飾的方法也行。

notify方法還有一個值得提出的是它會在當(dāng)前線程釋放了對象鎖以后隨機(jī)喚醒一個在該對象上等待的線程

看看一個例子: 

public void awakeAndWait(String thread, final long ms) {
    Thread notifyThread = new Thread() {
        public void run() {
            synchronized (monitor) {
                monitor.notify();
                System.out.println("Thread "
                        + Thread.currentThread().getName() + " Notify at "
                        + getTime());
                //保持了對象鎖的等待
                try {
                    Thread.sleep(ms);
                } catch (InterruptedException e) {
                }
            }
            //釋放了對象鎖之后的等待
            try {
                Thread.sleep(ms);
            } catch (InterruptedException e) {
            }
        };
    };
    notifyThread.setName(thread);
    notifyThread.start();
}

這個方法會喚醒一個在對象上等待的線程,并在兩次sleep后退出,注意的是一個sleep是在對象鎖內(nèi),而另一次則是在釋放了對象鎖以后,這時候運(yùn)行上面2個方法得到: 

 WaitAndNotifyTest test = new WaitAndNotifyTest();
test.waitOnce("1", Long.MAX_VALUE);// 在對象上等待無限長
test.waitOnce("2", Long.MAX_VALUE);// 在對象上等待無限長
test.waitOnce("3", Long.MAX_VALUE);// 在對象上等待無限長
try {// 延遲2s
    Thread.sleep(2000);
} catch (InterruptedException e) {
}
// 在喚醒一個在對象上等待的線程,本身執(zhí)行時間4s,2s是在對象鎖內(nèi)
//,2s是在釋放了對象鎖以后
test.awakeAndWait("3", 2000); 

執(zhí)行結(jié)果為:

寫道

Thread 1 Wait at 2011-05-06:10:57:04
Thread 2 Wait at 2011-05-06:10:57:04
Thread 3 Wait at 2011-05-06:10:57:04
Thread 3 Notify at 2011-05-06:10:57:06
Thread 1 Waked at 2011-05-06:10:57:08

2秒后喚醒了線程1,盡管它自己執(zhí)行花了4s,在釋放了對象鎖之后的2s不會影響線程1的執(zhí)行。

notifyAll()
JDK文檔 寫道

喚醒在此對象監(jiān)視器上等待的所有線程 。線程通過調(diào)用其中一個 wait 方法,在對象的監(jiān)視器上等待。
直到當(dāng)前線程放棄此對象上的鎖定,才能繼續(xù)執(zhí)行被喚醒的線程。被喚醒的線程將以常規(guī)方式與在該對象上主動同步的其他所有線程進(jìn)行競爭;例如,喚醒的線程在作為鎖定此對象的下一個線程方面沒有可靠的特權(quán)或劣勢。

此方法只應(yīng)由作為此對象監(jiān)視器的所有者的線程來調(diào)用。有關(guān)線程能夠成為監(jiān)視器所有者的方法的描述,請參閱 notify 方法。

拋出:
IllegalMonitorStateException – 如果當(dāng)前線程不是此對象監(jiān)視器的所有者。

與notify稍微有一點(diǎn)差別的是,它會喚醒所有的等待線程。

public void awakeAll(String thread) {
    Thread notifyThread = new Thread() {
        public void run() {
            synchronized (monitor) {
                monitor.notifyAll();
                System.out.println("Thread "
                        + Thread.currentThread().getName()
                        + " Notify all at " + getTime());
            }
        };
    };
    notifyThread.setName(thread);
    notifyThread.start();
}

執(zhí)行一下代碼: 

 WaitAndNotifyTest test = new WaitAndNotifyTest();
test.waitOnce("1", Long.MAX_VALUE);// 在對象上等待無限長
test.waitOnce("2", Long.MAX_VALUE);// 在對象上等待無限長
test.waitOnce("3", Long.MAX_VALUE);// 在對象上等待無限長
try {// 延遲2s
    Thread.sleep(2000);
} catch (InterruptedException e) {
}
test.awakeAll("4"); 

結(jié)果為:

寫道

Thread 1 Wait at 2011-05-06:10:59:15
Thread 3 Wait at 2011-05-06:10:59:15
Thread 2 Wait at 2011-05-06:10:59:15
Thread 4 Notify all at 2011-05-06:10:59:17
Thread 2 Waked at 2011-05-06:10:59:17
Thread 3 Waked at 2011-05-06:10:59:17
Thread 1 Waked at 2011-05-06:10:59:17

全部喚醒了。

總結(jié)
總結(jié)一下:大概有以下幾點(diǎn):

1.wait(),notify(),notifyAll()都需要在擁有對象監(jiān)視器的前提下執(zhí)行,否則會出現(xiàn)異常IllegalMonitorStateException。
2.多個線程可以同時在一個對象上等待。
3.notify()將隨機(jī)喚醒一個在對象上等待的線程,沒有一個都沒有,則什么都不做。
4.notify()喚醒的線程,將在notify()線程釋放了對象監(jiān)視器以后才執(zhí)行,并不是notify了以后馬上執(zhí)行。
5.Object的這些方法與Thread的sleep、interrupt相差還是很遠(yuǎn)的,不要混為一談了。


(###)

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多