欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JAVA中wait()和notify()如何使用詳解

 更新時間:2025年05月08日 10:28:41   作者:Lizhihao_  
這篇文章主要介紹了JAVA中wait()和notify()如何使用的相關資料,wait和notify必須在同步方法或同步塊中使用,并且調用對象必須一致,wait和sleep都可被interrupt喚醒,但wait會釋放鎖,而sleep不會,需要的朋友可以參考下

前言

大家應該都知道,線程之間是搶占式隨機執(zhí)行的,但是我們并不希望這樣。因為這樣非?;靵y,并不好去預估程序的執(zhí)行結果。我們甚至希望,線程之間能夠配合執(zhí)行,那么我們就可以使用wait()和notify()來做到。

一、wait()方法

wait有兩個方法:

wait():讓當前線程進入等待(阻塞)狀態(tài)。死等,沒有喚醒就會一直阻塞

wait(long timeout) :指定時間內,讓線程進入等待(阻塞)狀態(tài)。

1.wait()主要做的事

  • 使當前執(zhí)行代碼的線程進行等待。(把線程放到等待隊列中)
  • 釋放當前的鎖
  • 滿足條件被notify()喚醒,重新嘗試獲取這個鎖
    public static void main(String[] args) throws InterruptedException {
        Object object = new Object();

        System.out.println("wait 之前");

        /**
         * Object中有wait方法,通過Object對象調用wait方法
         * wait沒有參數(shù)的版本是默認死等
         * wait帶參數(shù)的版本是指定超時時間,如果超時了還沒有notify就繼續(xù)執(zhí)行
         *
         * 使用wait有三個操作:
         * (1)釋放鎖
         * (2)進入阻塞等待,準備接受通知
         * (3)收到通知之后喚醒,并且重新獲取鎖
         */

        /**
         * 因為wait會解鎖,所以wait必須在synchronized內部
         * 而且synchronized括號內的Object對象,必須和調用wait的是同一對象
         */
        synchronized(object) {
            object.wait();
        }
        System.out.println("wait 之后");

    }

2.wait()的結束條件

其他線程調?該對象的 notify ?法.

wait 等待時間超時 (wait ?法提供?個帶有 timeout 參數(shù)的版本, 來指定等待時間).

其他線程調?該等待線程的 interrupt ?法, 導致 wait 拋出 InterruptedException 異常,并清除中斷標志位(給程序員自由發(fā)揮的空間),并重新嘗試獲取鎖。
    public static void main(String[] args) throws InterruptedException {
        Object locker = new Object();

        Thread t1 = new Thread(() -> {
            //獲取當前線程
            Thread current = Thread.currentThread();
            int count = 0;
            //標志位默認為false,為true就是被中斷了
            while (!current.isInterrupted()) {
                //如果中斷位被清空了,不會執(zhí)行第二次
                System.out.println("t1線程第一次執(zhí)行" + count++);
                synchronized (locker) {
                    //因為Thread并沒有處理這個異常,所以必須在這里使用try-catch處理一下
                    try {
                        //開始等待
                        //如果被interrupt中斷會拋出異常,并清除中斷位
                        //并重新嘗試獲取鎖
                        locker.wait();
                    } catch (InterruptedException e) {
                        System.err.println("被interrupt喚醒");
                    }
                }
            }
        });

        t1.start();
        while (true) {
            Thread.sleep(1000);
            t1.interrupt();
        }
    }

3.有參數(shù)的wait()

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

        Thread t1 = new Thread(() -> {
            long start = System.currentTimeMillis();
            System.out.println("wait之前");
            synchronized (locker) {
                try {
                    locker.wait(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            long end = System.currentTimeMillis();
            System.out.println("wait之后 耗時:" + (end - start));
        });

        t1.start();

    }

結果:

二、notify()

notify?法是喚醒等待的線程,主要配合wait():

notify():喚醒同一對象調用正在wait()的線程,如果有多個線程正在wait()就會隨機喚醒一個線程

notifyAll():喚醒所有正在wait()的線程

1.notify()主要做的事

?法notify()也要在同步?法或同步塊中調?,該?法是?來通知那些可能等待該對象的對象鎖的其它線程,對其發(fā)出通知notify,并使它們重新獲取該對象的對象鎖。

如果有多個線程等待,則有線程調度器隨機挑選出?個呈 wait 狀態(tài)的線程。(并沒有 "先來后到")

在notify()?法后,當前線程不會?上釋放該對象鎖,要等到執(zhí)?notify()?法的線程將程序執(zhí)?完,也就是退出同步代碼塊之后才會釋放對象鎖。

    public static void main(String[] args) throws InterruptedException {
        Object locker = new Object();


        Thread t1 = new Thread(() -> {
            synchronized (locker) {

                System.out.println("wait之前~");

                try {
                    locker.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println("wait之后!");
            }
        });


        Thread t2 = new Thread(() -> {
            synchronized (locker) {

                System.out.println("notify之前");

                locker.notify();

                //notify之后,并不會馬上釋放鎖結束,至少會
                //把synchronized中的語句執(zhí)行完
                System.out.println("未解鎖之后的notify");
            }
            //看是否會執(zhí)行到這一條語句
            System.err.println("解鎖之后的notify");
        });

        t1.start();
        //防止執(zhí)行到notify了,t2還沒阻塞(wait)
        Thread.sleep(500);
        t2.start();

    }

結果分析:

注意事項:

2.notify() 會喚醒sleep()嗎?

    public static void main(String[] args) throws InterruptedException {
        Object locker = new Object();

        Thread t1 = new Thread(() -> {
            System.out.println("sleep睡眠");
            try {
                //sleep不需要在synchronized里
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("sleep睡醒了");
        });

        Thread t2 = new Thread(() -> {
            synchronized (locker) {
                System.out.println("notify之前");
                locker.notify();
                System.out.println("notify之后");
            }
        });

        t1.start();
        Thread.sleep(1000);
        t2.start();
    }

結果:

3.notifyAll()

 喚醒所有正在等待的線程

    public static void main(String[] args) throws InterruptedException {
        Object locker = new Object();
        Thread t1 = new Thread(() -> {
            System.out.println("t1線程開始");
            synchronized (locker) {
                try {
                    locker.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.err.println("t1線程結束");
        });
        Thread t2 = new Thread(() -> {
            System.out.println("t2線程開始");
            synchronized (locker) {
                try {
                    locker.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.err.println("t2線程結束");
        });
        Thread t3 = new Thread(() -> {
            System.out.println("t3線程開始");
            synchronized (locker) {
                try {
                    locker.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.err.println("t3線程結束");
        });
        Thread t4 = new Thread(() -> {
            synchronized (locker) {
                System.out.println("notify之前");
                locker.notifyAll();
                System.out.println("notify之后");
            }
        });

        t1.start();
        t2.start();
        t3.start();
        //保證上面的線程都已經執(zhí)行了wait
        Thread.sleep(1000);
        t4.start();
    }

三、調用 wait\notify\synchronized 使用的對象

 注意:wait和notify都必須放在synchronized中,不然會拋出異常:IllegalMonitorStateException

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

        Thread t1 = new Thread(() -> {
            System.out.println("t1線程開始");
            try {
                locker.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.err.println("t1線程結束");
        });

        Thread t4 = new Thread(() -> {
            try {
                Thread.sleep(1000);
                locker.notify();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        t1.start();
        t4.start();
    }

并且synchronized括號內部,必須和調用的是同一對象,不然依然會拋異常:

    public static void main(String[] args) {
        Object locker1 = new Object();
        Object locker2 = new Object();

        Thread t1 = new Thread(() -> {
            synchronized (locker1) {
                System.out.println("t1線程開始");
                try {
                    locker2.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.err.println("t1線程結束");
            }
        });

        Thread t4 = new Thread(() -> {
            synchronized (locker1) {
                try {
                    Thread.sleep(1000);
                    locker2.notify();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        });

        t1.start();
        t4.start();
    }

四、wait和sleep的比較/區(qū)別(面試題)

其實理論上 wait 和 sleep 完全是沒有可?性的,因為?個是?于線程之間的通信的,?個是讓線程阻塞?段時間。

相同點:

都會讓線程放棄執(zhí)行一段時間

都可以被interrupt喚醒,并且都會拋出 InterruptedException 異常,并且清空標志位

不同點:

wait是Object的方法,sleep是Thread的靜態(tài)方法

wait必須在synchronized中,sleep不需要

wait阻塞的時候釋放鎖,sleep并不會,sleep會抱著鎖一起阻塞

wait用于線程間通信(如生產者-消費者模型),sleep用于阻塞線程

總結

到此這篇關于JAVA中wait()和notify()如何使用的文章就介紹到這了,更多相關Java wait()和notify()內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • java實現(xiàn)多人聊天系統(tǒng)

    java實現(xiàn)多人聊天系統(tǒng)

    這篇文章主要為大家詳細介紹了java實現(xiàn)多人聊天系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-09-09
  • Mybatis如何傳入多個參數(shù)的實現(xiàn)代碼

    Mybatis如何傳入多個參數(shù)的實現(xiàn)代碼

    這篇文章主要介紹了Mybatis如何傳入多個參數(shù)的實現(xiàn)代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-12-12
  • ElasticSearch不停機重建索引延伸思考及優(yōu)化詳解

    ElasticSearch不停機重建索引延伸思考及優(yōu)化詳解

    這篇文章主要為大家介紹了ElasticSearch不停機重建索引延伸思考及優(yōu)化詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-02-02
  • SpringBoot中注解@ConfigurationProperties與@Value的區(qū)別與使用詳解

    SpringBoot中注解@ConfigurationProperties與@Value的區(qū)別與使用詳解

    本文主要介紹了SpringBoot中注解@ConfigurationProperties與@Value的區(qū)別與使用,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • Java三級菜單工具類實現(xiàn)方式

    Java三級菜單工具類實現(xiàn)方式

    這篇文章通過實例代碼給大家介紹Java三級菜單工具類實現(xiàn)方式,常用的三個字段,子級id、父級id、其次是數(shù)組children,本文結合實例代碼給大家介紹的非常詳細,需要的朋友參考下吧
    2024-05-05
  • 帶你了解Java數(shù)據(jù)結構和算法之無權無向圖

    帶你了解Java數(shù)據(jù)結構和算法之無權無向圖

    這篇文章主要為大家介紹了Java數(shù)據(jù)結構和算法之無權無向圖?,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-01-01
  • SpringBoot項目運行jar包啟動的步驟流程解析

    SpringBoot項目運行jar包啟動的步驟流程解析

    這篇文章主要介紹了SpringBoot項目運行jar包啟動的步驟流程,本文分步驟通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2020-07-07
  • Spring-AOP 靜態(tài)普通方法名匹配切面操作

    Spring-AOP 靜態(tài)普通方法名匹配切面操作

    這篇文章主要介紹了Spring-AOP 靜態(tài)普通方法名匹配切面操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Java結構型設計模式中建造者模式示例詳解

    Java結構型設計模式中建造者模式示例詳解

    建造者模式,是一種對象構建模式 它可以將復雜對象的建造過程抽象出來,使這個抽象過程的不同實現(xiàn)方法可以構造出不同表現(xiàn)的對象。本文將通過示例講解建造者模式,需要的可以參考一下
    2022-09-09
  • 基于Java的guava開源庫工具類

    基于Java的guava開源庫工具類

    guava是谷歌基于java封裝好的開源庫,這篇文章主要通過介紹幾個好用的guava工具類,感興趣的朋友可以參考下面文章內容
    2021-09-09

最新評論