最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java基本教程之java線程等待與java喚醒線程 java多線程教程

 更新時(shí)間:2014年01月14日 10:18:09   作者:  
這篇文章主要介紹了對(duì)線程等待/喚醒方法,文中使用了多個(gè)示例,大家參考使用吧

本章,會(huì)對(duì)線程等待/喚醒方法進(jìn)行介紹。涉及到的內(nèi)容包括:
1. wait(), notify(), notifyAll()等方法介紹
2. wait()和notify()
3. wait(long timeout)和notify()
4. wait() 和 notifyAll()
5. 為什么notify(), wait()等函數(shù)定義在Object中,而不是Thread中

wait(), notify(), notifyAll()等方法介紹
在Object.java中,定義了wait(), notify()和notifyAll()等接口。wait()的作用是讓當(dāng)前線程進(jìn)入等待狀態(tài),同時(shí),wait()也會(huì)讓當(dāng)前線程釋放它所持有的鎖。而notify()和notifyAll()的作用,則是喚醒當(dāng)前對(duì)象上的等待線程;notify()是喚醒單個(gè)線程,而notifyAll()是喚醒所有的線程。

Object類中關(guān)于等待/喚醒的API詳細(xì)信息如下:
notify()        -- 喚醒在此對(duì)象監(jiān)視器上等待的單個(gè)線程。
notifyAll()   -- 喚醒在此對(duì)象監(jiān)視器上等待的所有線程。
wait()                                         -- 讓當(dāng)前線程處于“等待(阻塞)狀態(tài)”,“直到其他線程調(diào)用此對(duì)象的 notify() 方法或 notifyAll() 方法”,當(dāng)前線程被喚醒(進(jìn)入“就緒狀態(tài)”)。
wait(long timeout)                    -- 讓當(dāng)前線程處于“等待(阻塞)狀態(tài)”,“直到其他線程調(diào)用此對(duì)象的 notify() 方法或 notifyAll() 方法,或者超過指定的時(shí)間量”,當(dāng)前線程被喚醒(進(jìn)入“就緒狀態(tài)”)。
wait(long timeout, int nanos)  -- 讓當(dāng)前線程處于“等待(阻塞)狀態(tài)”,“直到其他線程調(diào)用此對(duì)象的 notify() 方法或 notifyAll() 方法,或者其他某個(gè)線程中斷當(dāng)前線程,或者已超過某個(gè)實(shí)際時(shí)間量”,當(dāng)前線程被喚醒(進(jìn)入“就緒狀態(tài)”)。


2. wait()和notify()示例
下面通過示例演示"wait()和notify()配合使用的情形"。

復(fù)制代碼 代碼如下:

// WaitTest.java的源碼
class ThreadA extends Thread{

    public ThreadA(String name) {
        super(name);
    }

    public void run() {
        synchronized (this) {
            System.out.println(Thread.currentThread().getName()+" call notify()");
            // 喚醒當(dāng)前的wait線程
            notify();
        }
    }
}

public class WaitTest {

    public static void main(String[] args) {

        ThreadA t1 = new ThreadA("t1");

        synchronized(t1) {
            try {
                // 啟動(dòng)“線程t1”
                System.out.println(Thread.currentThread().getName()+" start t1");
                t1.start();

                // 主線程等待t1通過notify()喚醒。
                System.out.println(Thread.currentThread().getName()+" wait()");
                t1.wait();

                System.out.println(Thread.currentThread().getName()+" continue");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

運(yùn)行結(jié)果:

復(fù)制代碼 代碼如下:

main start t1
main wait()
t1 call notify()
main continue

結(jié)果說明:
如下圖,說明了“主線程”和“線程t1”的流程。

(01) 注意,圖中"主線程" 代表“主線程main”。"線程t1" 代表WaitTest中啟動(dòng)的“線程t1”。 而“鎖” 代表“t1這個(gè)對(duì)象的同步鎖”。
(02) “主線程”通過 new ThreadA("t1") 新建“線程t1”。隨后通過synchronized(t1)獲取“t1對(duì)象的同步鎖”。然后調(diào)用t1.start()啟動(dòng)“線程t1”。
(03) “主線程”執(zhí)行t1.wait() 釋放“t1對(duì)象的鎖”并且進(jìn)入“等待(阻塞)狀態(tài)”。等待t1對(duì)象上的線程通過notify() 或 notifyAll()將其喚醒。
(04) “線程t1”運(yùn)行之后,通過synchronized(this)獲取“當(dāng)前對(duì)象的鎖”;接著調(diào)用notify()喚醒“當(dāng)前對(duì)象上的等待線程”,也就是喚醒“主線程”。
(05) “線程t1”運(yùn)行完畢之后,釋放“當(dāng)前對(duì)象的鎖”。緊接著,“主線程”獲取“t1對(duì)象的鎖”,然后接著運(yùn)行。


對(duì)于上面的代碼?曾經(jīng)有個(gè)朋友問到過:t1.wait()應(yīng)該是讓“線程t1”等待;但是,為什么卻是讓“主線程main”等待了呢?
在解答該問題前,我們先看看jdk文檔中關(guān)于wait的一段介紹:

復(fù)制代碼 代碼如下:

Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object.
In other words, this method behaves exactly as if it simply performs the call wait(0).
The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the notify method or the notifyAll method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.

中文意思大概是:

引起“當(dāng)前線程”等待,直到另外一個(gè)線程調(diào)用notify()或notifyAll()喚醒該線程。換句話說,這個(gè)方法和wait(0)的效果一樣!(補(bǔ)充,對(duì)于wait(long millis)方法,當(dāng)millis為0時(shí),表示無(wú)限等待,直到被notify()或notifyAll()喚醒)。
“當(dāng)前線程”在調(diào)用wait()時(shí),必須擁有該對(duì)象的同步鎖。該線程調(diào)用wait()之后,會(huì)釋放該鎖;然后一直等待直到“其它線程”調(diào)用對(duì)象的同步鎖的notify()或notifyAll()方法。然后,該線程繼續(xù)等待直到它重新獲取“該對(duì)象的同步鎖”,然后就可以接著運(yùn)行。
注意:jdk的解釋中,說wait()的作用是讓“當(dāng)前線程”等待,而“當(dāng)前線程”是指正在cpu上運(yùn)行的線程!
這也意味著,雖然t1.wait()是通過“線程t1”調(diào)用的wait()方法,但是調(diào)用t1.wait()的地方是在“主線程main”中。而主線程必須是“當(dāng)前線程”,也就是運(yùn)行狀態(tài),才可以執(zhí)行t1.wait()。所以,此時(shí)的“當(dāng)前線程”是“主線程main”!因此,t1.wait()是讓“主線程”等待,而不是“線程t1”!


3. wait(long timeout)和notify()
wait(long timeout)會(huì)讓當(dāng)前線程處于“等待(阻塞)狀態(tài)”,“直到其他線程調(diào)用此對(duì)象的 notify() 方法或 notifyAll() 方法,或者超過指定的時(shí)間量”,當(dāng)前線程被喚醒(進(jìn)入“就緒狀態(tài)”)。
下面的示例就是演示wait(long timeout)在超時(shí)情況下,線程被喚醒的情況。

復(fù)制代碼 代碼如下:

// WaitTimeoutTest.java的源碼
class ThreadA extends Thread{

    public ThreadA(String name) {
        super(name);
    }

    public void run() {
        System.out.println(Thread.currentThread().getName() + " run ");
        // 死循環(huán),不斷運(yùn)行。
        while(true)

    }
}

public class WaitTimeoutTest {

    public static void main(String[] args) {

        ThreadA t1 = new ThreadA("t1");

        synchronized(t1) {
            try {
                // 啟動(dòng)“線程t1”
                System.out.println(Thread.currentThread().getName() + " start t1");
                t1.start();

                // 主線程等待t1通過notify()喚醒 或 notifyAll()喚醒,或超過3000ms延時(shí);然后才被喚醒。
                System.out.println(Thread.currentThread().getName() + " call wait ");
                t1.wait(3000);

                System.out.println(Thread.currentThread().getName() + " continue");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

運(yùn)行結(jié)果:

復(fù)制代碼 代碼如下:

main start t1
main call wait
t1 run                  // 大約3秒之后...輸出“main continue”
main continue

結(jié)果說明:
如下圖,說明了“主線程”和“線程t1”的流程。
(01) 注意,圖中"主線程" 代表WaitTimeoutTest主線程(即,線程main)。"線程t1" 代表WaitTest中啟動(dòng)的線程t1。 而“鎖” 代表“t1這個(gè)對(duì)象的同步鎖”。
(02) 主線程main執(zhí)行t1.start()啟動(dòng)“線程t1”。
(03) 主線程main執(zhí)行t1.wait(3000),此時(shí),主線程進(jìn)入“阻塞狀態(tài)”。需要“用于t1對(duì)象鎖的線程通過notify() 或者 notifyAll()將其喚醒” 或者 “超時(shí)3000ms之后”,主線程main才進(jìn)入到“就緒狀態(tài)”,然后才可以運(yùn)行。
(04) “線程t1”運(yùn)行之后,進(jìn)入了死循環(huán),一直不斷的運(yùn)行。
(05) 超時(shí)3000ms之后,主線程main會(huì)進(jìn)入到“就緒狀態(tài)”,然后接著進(jìn)入“運(yùn)行狀態(tài)”。

4. wait() 和 notifyAll()
通過前面的示例,我們知道 notify() 可以喚醒在此對(duì)象監(jiān)視器上等待的單個(gè)線程。
下面,我們通過示例演示notifyAll()的用法;它的作用是喚醒在此對(duì)象監(jiān)視器上等待的所有線程。

復(fù)制代碼 代碼如下:

public class NotifyAllTest {

    private static Object obj = new Object();
    public static void main(String[] args) {

        ThreadA t1 = new ThreadA("t1");
        ThreadA t2 = new ThreadA("t2");
        ThreadA t3 = new ThreadA("t3");
        t1.start();
        t2.start();
        t3.start();

        try {
            System.out.println(Thread.currentThread().getName()+" sleep(3000)");
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        synchronized(obj) {
            // 主線程等待喚醒。
            System.out.println(Thread.currentThread().getName()+" notifyAll()");
            obj.notifyAll();
        }
    }

    static class ThreadA extends Thread{

        public ThreadA(String name){
            super(name);
        }

        public void run() {
            synchronized (obj) {
                try {
                    // 打印輸出結(jié)果
                    System.out.println(Thread.currentThread().getName() + " wait");

                    // 喚醒當(dāng)前的wait線程
                    obj.wait();

                    // 打印輸出結(jié)果
                    System.out.println(Thread.currentThread().getName() + " continue");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

運(yùn)行結(jié)果:

復(fù)制代碼 代碼如下:

t1 wait
main sleep(3000)
t3 wait
t2 wait
main notifyAll()
t2 continue
t3 continue
t1 continue

結(jié)果說明:
參考下面的流程圖。
(01) 主線程中新建并且啟動(dòng)了3個(gè)線程"t1", "t2"和"t3"。
(02) 主線程通過sleep(3000)休眠3秒。在主線程休眠3秒的過程中,我們假設(shè)"t1", "t2"和"t3"這3個(gè)線程都運(yùn)行了。以"t1"為例,當(dāng)它運(yùn)行的時(shí)候,它會(huì)執(zhí)行obj.wait()等待其它線程通過notify()或額nofityAll()來(lái)喚醒它;相同的道理,"t2"和"t3"也會(huì)等待其它線程通過nofity()或nofityAll()來(lái)喚醒它們。
(03) 主線程休眠3秒之后,接著運(yùn)行。執(zhí)行 obj.notifyAll() 喚醒obj上的等待線程,即喚醒"t1", "t2"和"t3"這3個(gè)線程。 緊接著,主線程的synchronized(obj)運(yùn)行完畢之后,主線程釋放“obj鎖”。這樣,"t1", "t2"和"t3"就可以獲取“obj鎖”而繼續(xù)運(yùn)行了!




5. 為什么notify(), wait()等函數(shù)定義在Object中,而不是Thread中
Object中的wait(), notify()等函數(shù),和synchronized一樣,會(huì)對(duì)“對(duì)象的同步鎖”進(jìn)行操作。

wait()會(huì)使“當(dāng)前線程”等待,因?yàn)榫€程進(jìn)入等待狀態(tài),所以線程應(yīng)該釋放它鎖持有的“同步鎖”,否則其它線程獲取不到該“同步鎖”而無(wú)法運(yùn)行!
OK,線程調(diào)用wait()之后,會(huì)釋放它鎖持有的“同步鎖”;而且,根據(jù)前面的介紹,我們知道:等待線程可以被notify()或notifyAll()喚醒?,F(xiàn)在,請(qǐng)思考一個(gè)問題:notify()是依據(jù)什么喚醒等待線程的?或者說,wait()等待線程和notify()之間是通過什么關(guān)聯(lián)起來(lái)的?答案是:依據(jù)“對(duì)象的同步鎖”。

負(fù)責(zé)喚醒等待線程的那個(gè)線程(我們稱為“喚醒線程”),它只有在獲取“該對(duì)象的同步鎖”(這里的同步鎖必須和等待線程的同步鎖是同一個(gè)),并且調(diào)用notify()或notifyAll()方法之后,才能喚醒等待線程。雖然,等待線程被喚醒;但是,它不能立刻執(zhí)行,因?yàn)閱拘丫€程還持有“該對(duì)象的同步鎖”。必須等到喚醒線程釋放了“對(duì)象的同步鎖”之后,等待線程才能獲取到“對(duì)象的同步鎖”進(jìn)而繼續(xù)運(yùn)行。

總之,notify(), wait()依賴于“同步鎖”,而“同步鎖”是對(duì)象鎖持有,并且每個(gè)對(duì)象有且僅有一個(gè)!這就是為什么notify(), wait()等函數(shù)定義在Object類,而不是Thread類中的原因。

相關(guān)文章

  • Java設(shè)計(jì)模式之單例模式簡(jiǎn)析

    Java設(shè)計(jì)模式之單例模式簡(jiǎn)析

    這篇文章主要介紹了Java設(shè)計(jì)模式之單例模式簡(jiǎn)析,單例模式是常用的設(shè)計(jì)模式,在我們的系統(tǒng)乃至在框架中都普遍被用到,單例模式就是使一個(gè)類有且只有一個(gè)實(shí)例用于外部訪問,這樣大大的節(jié)省了系統(tǒng)的資源,需要的朋友可以參考下
    2023-12-12
  • Java職責(zé)鏈模式的深入了解

    Java職責(zé)鏈模式的深入了解

    這篇文章主要為大家介紹了Java職責(zé)鏈模式,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-01-01
  • JAVA 統(tǒng)計(jì)字符串中中文,英文,數(shù)字,空格,特殊字符的個(gè)數(shù)

    JAVA 統(tǒng)計(jì)字符串中中文,英文,數(shù)字,空格,特殊字符的個(gè)數(shù)

    這篇文章主要介紹了JAVA 統(tǒng)計(jì)字符串中中文,英文,數(shù)字,空格,特殊字符的個(gè)數(shù) ,本文通過一段代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-06-06
  • Spring security中的授權(quán)

    Spring security中的授權(quán)

    本篇為大家?guī)?lái)Spring security的授權(quán),首先要理解一些概念,有關(guān)于:權(quán)限、角色、安全上下文、訪問控制表達(dá)式、方法級(jí)安全性、訪問決策管理器,這篇文章主要介紹了Spring security中的授權(quán),需要的朋友可以參考下
    2024-01-01
  • SpringBoot3集成Swagger3的詳細(xì)教程

    SpringBoot3集成Swagger3的詳細(xì)教程

    Swagger 3(OpenAPI 3.0)提供了更加強(qiáng)大和靈活的API文檔生成能力,本教程將指導(dǎo)您如何在Spring Boot 3項(xiàng)目中集成Swagger3,并使用Knife4j作為UI界面,需要的朋友可以參考下
    2024-03-03
  • java:程序包javafx.geometry不存在問題及解決

    java:程序包javafx.geometry不存在問題及解決

    這篇文章主要介紹了java:程序包javafx.geometry不存在問題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • SpringBoot快速遷移至Quarkus的方法步驟

    SpringBoot快速遷移至Quarkus的方法步驟

    這篇文章主要介紹了SpringBoot快速遷移至Quarkus的方法步驟。文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • SpringBoot動(dòng)態(tài)定時(shí)任務(wù)實(shí)現(xiàn)完整版

    SpringBoot動(dòng)態(tài)定時(shí)任務(wù)實(shí)現(xiàn)完整版

    最近有幸要開發(fā)個(gè)動(dòng)態(tài)定時(shí)任務(wù),這里簡(jiǎn)單再梳理一下,下面這篇文章主要給大家介紹了關(guān)于SpringBoot動(dòng)態(tài)定時(shí)任務(wù)實(shí)現(xiàn)的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-02-02
  • 深入解析Java的Struts框架中的控制器DispatchAction

    深入解析Java的Struts框架中的控制器DispatchAction

    這篇文章主要介紹了深入解析Java的Struts框架中的控制器DispatchAction,Struts是Java的SSH三大web開發(fā)框架之一,需要的朋友可以參考下
    2015-12-12
  • Java如何向主函數(shù)main中傳入?yún)?shù)

    Java如何向主函數(shù)main中傳入?yún)?shù)

    這篇文章主要介紹了Java如何向主函數(shù)main中傳入?yún)?shù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-02-02

最新評(píng)論

朝阳区| 拜泉县| 海丰县| 徐水县| 达孜县| 开化县| 通江县| 宁晋县| 揭东县| 雅江县| 孟村| 青田县| 康定县| 潢川县| 岳阳市| 百色市| 石首市| 阳西县| 通化县| 手机| 大邑县| 神农架林区| 宝丰县| 宿松县| 海兴县| 克东县| 岑溪市| 乌审旗| 永宁县| 万源市| 乌拉特中旗| 陆川县| 嘉义市| 漳浦县| 乐都县| 吴江市| 巴中市| 泾源县| 稷山县| 色达县| 溧水县|