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

java使用wait和notify實現(xiàn)線程通信

 更新時間:2023年10月07日 10:40:53   作者:終有救贖  
這篇文章主要為大家詳細介紹了java如何使用wait和notify實現(xiàn)線程之間通信,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下

一. 為什么需要線程通信

線程是并發(fā)并行的執(zhí)行,表現(xiàn)出來是線程隨機執(zhí)行,但是我們在實際應用中對線程的執(zhí)行順序是有要求的,這就需要用到線程通信

線程通信為什么不使用優(yōu)先級來來解決線程的運行順序?

總的優(yōu)先級是由線程pcb中的優(yōu)先級信息和線程等待時間共同決定的,所以一般開發(fā)中不會依賴優(yōu)先級來表示線程的執(zhí)行順序

看下面這樣的一個場景:面包房的例子來描述生產(chǎn)者消費者模型

有一個面包房,里面有面包師傅和顧客,對應我們的生產(chǎn)者和消費者,而面包房有一個庫存用來存儲面包,當庫存滿了之后就不在生產(chǎn),同時消費者也在購買面包,當庫存面包賣完了之后,消費者必須等待新的面包生產(chǎn)出來才能繼續(xù)購買

分析: 對于何時停止生產(chǎn)何時停止消費就需要應用到線程通信來準確的傳達生產(chǎn)和消費信息

二. wait和notify方法

wait():讓當前線程持有的對象鎖釋放并等待

wait(long timeout):對應的參數(shù)是線程等待的時間

notify():喚醒使用同一個對象調(diào)用wait進入等待的線程,重新競爭對象鎖

notifyAll():如果有多個線程等待,notifyAll是全部喚醒 ,notify是隨機喚醒一個

注意:

這幾個方法都屬于Object類中的方法

必須使用在synchronized同步代碼塊/同步方法中

哪個對象加鎖,就是用哪個對象wait,notify

調(diào)用notify后不是立即喚醒,而是等synchronized結(jié)束以后,才喚醒

1. wait()方法

調(diào)用wait方法后:

  • 使執(zhí)行當前代碼的線程進行等待(線程放在等待隊列)
  • 釋放當前的鎖
  • 滿足一定條件時被喚醒,重新嘗試獲取鎖

wait等待結(jié)束的條件:

  • 其他線程調(diào)用該對象的notify方法
  • wait等待時間超時(timeout參數(shù)來指定等待時間)
  • 其他線程調(diào)用interrupted方法,導致wait拋出InterruptedException異常

2. notify()方法

當使用wait不帶參數(shù)的方法時,喚醒線程等待就需要使用notify方法

  • 這個方法是喚醒那些等待該對象的對象鎖的線程,使他們可以重新獲取該對象的對象鎖
  • 如果有多個線程等待,則由線程調(diào)度器隨機挑選出一個呈wait 狀態(tài)的線程(不存在先來后到)
  • 在notify()方法后,當前線程不會馬上釋放該對象鎖,要等到執(zhí)行notify()方法的線程將程序執(zhí)行完,也就是退出同步代碼塊之后才會釋放對象鎖

3. notifyAll()方法

該方法和notify()方法作用一樣,只是喚醒的時候,將所有等待的線程都喚醒

notify()方法只是隨機喚醒一個線程

三. 使用wait和notify實現(xiàn)面包房業(yè)務 

前提說明:

有2個面包師傅,面包師傅一次可以做出兩個面包

倉庫可以存儲100個面包

有10個消費者,每個消費者一次購買一個面包

注意:

消費和生產(chǎn)是同時并發(fā)并行進行的,不是一次生產(chǎn)一次消費

實現(xiàn)代碼:

public class Bakery {
    private static int total;//庫存
    public static void main(String[] args) {
        Producer producer = new Producer();
        for(int i = 0;i < 2;i++){
            new Thread(producer,"面包師傅-"+(i-1)).start();
        }
        Consumer consumer = new Consumer();
        for(int i = 0;i < 10;i++){
            new Thread(consumer,"消費者-"+(i-1)).start();
        }
    }
    private static class Producer implements Runnable{
        private int num = 3; //生產(chǎn)者每次生產(chǎn)三個面包
        @Override
        public void run() {
            try {
                while(true){ //一直生產(chǎn)
                    synchronized (Bakery.class){
                        while((total+num)>100){ //倉庫滿了,生產(chǎn)者等待
                            Bakery.class.wait();
                        }
                        //等待解除
                        total += num;
                        System.out.println(Thread.currentThread().getName()+"生產(chǎn)面包,庫存:"+total);
                        Thread.sleep(500);
                        Bakery.class.notifyAll(); //喚醒生產(chǎn)
                    }
                    Thread.sleep(500);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    private static class Consumer implements Runnable{
        private int num = 1; //消費者每次消費1個面包
        @Override
        public void run() {
            try {
                while(true){ //一直消費
                    synchronized (Bakery.class){
                        while((total-num)<0){ //倉庫空了,消費者等待
                            Bakery.class.wait();
                        }
                        //解除消費者等待
                        total -= num;
                        System.out.println(Thread.currentThread().getName()+"消費面包,庫存:"+total);
                        Thread.sleep(500);
                        Bakery.class.notifyAll(); //喚醒消費
                    }
                    Thread.sleep(500);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

部分打印結(jié)果:

四. 阻塞隊列

阻塞隊列是一個特殊的隊列,也遵循“先進先出”的原則,它是線程安全的隊列結(jié)構(gòu)

特性: 典型的生產(chǎn)者消費者模型,一般用于做任務的解耦和消峰

隊列滿的時候,入隊列就堵塞等待(生產(chǎn)),直到有其他線程從隊列中取走元素

隊列空的時候,出隊列就堵塞等待(消費),直到有其他線程往隊列中插入元素

1. 生產(chǎn)者消費者模型

生產(chǎn)者消費者模式就是通過一個容器來解決生產(chǎn)者和消費者的強耦合問題

生產(chǎn)者和消費者彼此之間不直接通信,而通過阻塞隊列來進行通信,所以生產(chǎn)者生產(chǎn)完數(shù)據(jù)之后等待消費者處理,直接扔給阻塞隊列,消費者不找生產(chǎn)者要數(shù)據(jù),而是直接從阻塞隊列里取

阻塞隊列就相當于一個緩沖區(qū),平衡了生產(chǎn)者和消費者的處理能力 阻塞隊列也能使生產(chǎn)者和消費者之間解耦

上述面包房業(yè)務的實現(xiàn)就是生產(chǎn)者消費者模型的一個實例

2. 標準庫中的阻塞隊列

在 Java 標準庫中內(nèi)置了阻塞隊列, 如果我們需要在一些程序中使用阻塞隊列, 直接使用標準庫中的即可

BlockingQueue 是一個接口. 真正實現(xiàn)的類是 LinkedBlockingQueue

put 方法用于阻塞式的入隊列, take 用于阻塞式的出隊列

BlockingQueue 也有 offer, poll, peek 等方法, 但是這些方法不帶有阻塞特性

        BlockingDeque<String> queue = new LinkedBlockingDeque<>();
        queue.put("hello");
        //如果隊列為空,直接出出隊列就會阻塞
        String ret = queue.take();
        System.out.println(ret);

3. 阻塞隊列的模擬實現(xiàn)

這里使用數(shù)組實現(xiàn)一個循環(huán)隊列來模擬阻塞隊列

  • 當隊列為空的時候,就不能取元素了,就進入wait等待,當有元素存放時,喚醒
  • 當隊列為滿的時候,就不能存元素了,就進入wait等待,當鈾元素取出時,喚醒

實現(xiàn)代碼:

public class MyBlockingQueue {
    //使用數(shù)組實現(xiàn)一個循環(huán)隊列,隊列里面存放的是線程要執(zhí)行的任務
    private Runnable[] tasks;
    //隊列中任務的數(shù)量,根據(jù)數(shù)量來判斷是否可以存取
    private int count;
    private int putIndex; //存放任務位置
    private int takeIndex; //取出任務位置
    //有參的構(gòu)造方法,表示隊列容量
    public MyBlockingQueue(int size){
        tasks = new Runnable[size];
    }
    //存任務
    public void put(Runnable task){
        try {
            synchronized (MyBlockingQueue.class){
                //如果隊列容量滿了,則存任務等待
                while(count == tasks.length){
                    MyBlockingQueue.class.wait();
                }
                tasks[putIndex] = task; //將任務放入數(shù)組
                putIndex = (putIndex+1) % tasks.length; //更新存任務位置
                count++; //更新存放數(shù)量
                MyBlockingQueue.class.notifyAll(); //喚醒取任務
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    //取任務
    public Runnable take(){
        try {
            synchronized (MyBlockingQueue.class){
                //如果隊列任務為空,則取任務等待
                while(count==0){
                    MyBlockingQueue.class.wait();
                }
                //取任務
                Runnable task = tasks[takeIndex];
                takeIndex = (takeIndex+1) % tasks.length; //更新取任務位置
                count--; //更新存放數(shù)量
                MyBlockingQueue.class.notifyAll(); //喚醒存任務
                return task;
            }
        } catch (InterruptedException e) {
           throw new RuntimeException("存放任務出錯",e);
        }
    }
}

五. wait和sleep的區(qū)別(面試題)

相同點:都可以讓線程放棄執(zhí)行一段時間

不同點:

wait用于線程通信,讓線程在等待隊列中等待

sleep讓線程阻塞一段時間,阻塞在阻塞隊列中

wait需要搭配synchronized使用,sleep不用搭配

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

以上就是java使用wait和notify實現(xiàn)線程通信的詳細內(nèi)容,更多關于java wait notify的資料請關注腳本之家其它相關文章!

相關文章

  • java線程池實現(xiàn)批量下載文件

    java線程池實現(xiàn)批量下載文件

    這篇文章主要為大家詳細介紹了java線程池實現(xiàn)批量下載文件,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-07-07
  • java中instanceof的作用及說明

    java中instanceof的作用及說明

    instanceof關鍵字用于檢查一個對象是否是特定類的實例或其子類或?qū)崿F(xiàn)了該類的接口,它可以幫助進行類型檢查、安全類型轉(zhuǎn)換、多態(tài)性處理和接口實現(xiàn)檢查,使用時需要注意其右邊必須是類名或接口名,不能用于基本數(shù)據(jù)類型
    2025-10-10
  • Spring Cloud引入Eureka組件,完善服務治理

    Spring Cloud引入Eureka組件,完善服務治理

    這篇文章主要介紹了Spring Cloud引入Eureka組件,完善服務治理的過程詳解,幫助大家更好的理解和使用spring cloud,感興趣的朋友可以了解下
    2021-02-02
  • jfinal添加jcaptcha驗證碼實現(xiàn)方法

    jfinal添加jcaptcha驗證碼實現(xiàn)方法

    這篇文章主要介紹了jfinal的jcaptcha驗證碼實現(xiàn)方法,大家參考使用吧
    2014-01-01
  • 關于SpringBoot使用@Async的總結(jié)

    關于SpringBoot使用@Async的總結(jié)

    這篇文章主要介紹了關于SpringBoot使用@Async的總結(jié),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • 解決Mybatis報錯:org.apache.ibatis.reflection.ReflectionException: There is no getter for property named問題

    解決Mybatis報錯:org.apache.ibatis.reflection.ReflectionException

    文章主要討論了在使用MyBatis進行數(shù)據(jù)庫操作時遇到的幾個常見問題及其解決方法,首先,文章指出如果DTO類中沒有定義getter和setter方法,會導致反射異常,解決方法是使用Lombok的@Data注解自動生成這些方法
    2025-01-01
  • java實現(xiàn)連接mysql數(shù)據(jù)庫單元測試查詢數(shù)據(jù)的實例代碼

    java實現(xiàn)連接mysql數(shù)據(jù)庫單元測試查詢數(shù)據(jù)的實例代碼

    下面小編就為大家?guī)硪黄猨ava實現(xiàn)連接mysql數(shù)據(jù)庫單元測試查詢數(shù)據(jù)的實例代碼。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-10-10
  • Spring?MVC全局異常處理實戰(zhàn)詳細指南

    Spring?MVC全局異常處理實戰(zhàn)詳細指南

    在Spring MVC框架中統(tǒng)一異常處理是一項重要的功能,它能夠幫助開發(fā)者集中管理并標準化系統(tǒng)中的異常處理流程,提高代碼的可讀性和可維護性,這篇文章主要介紹了Spring?MVC全局異常處理實戰(zhàn)的相關資料,需要的朋友可以參考下
    2026-02-02
  • SpringBoot中@Import注解的使用方式

    SpringBoot中@Import注解的使用方式

    這篇文章主要介紹了SpringBoot中@Import注解的使用方式,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-05-05
  • java實現(xiàn)單機版五子棋小游戲

    java實現(xiàn)單機版五子棋小游戲

    這篇文章主要為大家詳細介紹了java實現(xiàn)單機版五子棋小游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-12-12

最新評論

嵊州市| 大名县| 长岭县| 罗甸县| 新干县| 开原市| 正定县| 伊吾县| 海口市| 宜州市| 唐河县| 敖汉旗| 嘉义市| 亳州市| 洛南县| 闻喜县| 米脂县| 桦川县| 宜州市| 康乐县| 石首市| 习水县| 浠水县| 克拉玛依市| 共和县| 宁城县| 宜黄县| 高安市| 德阳市| 合山市| 邓州市| 洛宁县| 潜江市| 莲花县| 深水埗区| 青铜峡市| 长子县| 兰州市| 荣昌县| 田阳县| 资溪县|