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

Java使用wait和notify實(shí)現(xiàn)線程之間的通信

 更新時(shí)間:2022年04月12日 11:58:12   作者:Java猿~  
Java 線程通信是將多個(gè)獨(dú)立的線程個(gè)體進(jìn)行關(guān)聯(lián)處理,使得線程與線程之間能進(jìn)行相互通信,下面這篇文章主要給大家介紹了關(guān)于Java使用wait和notify實(shí)現(xiàn)線程之間通信的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下

??一. 為什么需要線程通信

線程是并發(fā)并行的執(zhí)行,表現(xiàn)出來(lái)是線程隨機(jī)執(zhí)行,但是我們?cè)趯?shí)際應(yīng)用中對(duì)線程的執(zhí)行順序是有要求的,這就需要用到線程通信

??線程通信為什么不使用優(yōu)先級(jí)來(lái)來(lái)解決線程的運(yùn)行順序?

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

??看下面這樣的一個(gè)場(chǎng)景:面包房的例子來(lái)描述生產(chǎn)者消費(fèi)者模型

有一個(gè)面包房,里面有面包師傅和顧客,對(duì)應(yīng)我們的生產(chǎn)者和消費(fèi)者,而面包房有一個(gè)庫(kù)存用來(lái)存儲(chǔ)面包,當(dāng)庫(kù)存滿了之后就不在生產(chǎn),同時(shí)消費(fèi)者也在購(gòu)買面包,當(dāng)庫(kù)存面包賣完了之后,消費(fèi)者必須等待新的面包生產(chǎn)出來(lái)才能繼續(xù)購(gòu)買

分析:對(duì)于何時(shí)停止生產(chǎn)何時(shí)停止消費(fèi)就需要應(yīng)用到線程通信來(lái)準(zhǔn)確的傳達(dá)生產(chǎn)和消費(fèi)信息

??二. wait和notify方法

??wait():讓當(dāng)前線程持有的對(duì)象鎖釋放并等待

??wait(long timeout):對(duì)應(yīng)的參數(shù)是線程等待的時(shí)間

??notify():?jiǎn)拘咽褂猛粋€(gè)對(duì)象調(diào)用wait進(jìn)入等待的線程,重新競(jìng)爭(zhēng)對(duì)象鎖

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

??‍???注意:

??這幾個(gè)方法都屬于Object類中的方法

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

??哪個(gè)對(duì)象加鎖,就是用哪個(gè)對(duì)象wait,notify

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

??1. wait()方法

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

??使執(zhí)行當(dāng)前代碼的線程進(jìn)行等待(線程放在等待隊(duì)列)

??釋放當(dāng)前的鎖

??滿足一定條件時(shí)被喚醒,重新嘗試獲取鎖

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

??其他線程調(diào)用該對(duì)象的notify方法

??wait等待時(shí)間超時(shí)(timeout參數(shù)來(lái)指定等待時(shí)間)

??其他線程調(diào)用interrupted方法,導(dǎo)致wait拋出InterruptedException異常

??2. notify()方法 

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

??這個(gè)方法是喚醒那些等待該對(duì)象的對(duì)象鎖的線程,使他們可以重新獲取該對(duì)象的對(duì)象鎖 

??如果有多個(gè)線程等待,則由線程調(diào)度器隨機(jī)挑選出一個(gè)呈wait 狀態(tài)的線程(不存在先來(lái)后到)

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

??3. notifyAll()方法

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

notify()方法只是隨機(jī)喚醒一個(gè)線程 

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

前提說(shuō)明:

有2個(gè)面包師傅,面包師傅一次可以做出兩個(gè)面包

倉(cāng)庫(kù)可以存儲(chǔ)100個(gè)面包

有10個(gè)消費(fèi)者,每個(gè)消費(fèi)者一次購(gòu)買一個(gè)面包 

??‍???注意:

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

??‍???實(shí)現(xiàn)代碼:

public class Bakery {
    private static int total;//庫(kù)存
 
    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,"消費(fèi)者-"+(i-1)).start();
        }
    }
    private static class Producer implements Runnable{
        private int num = 3; //生產(chǎn)者每次生產(chǎn)三個(gè)面包
        @Override
        public void run() {
            try {
                while(true){ //一直生產(chǎn)
                    synchronized (Bakery.class){
                        while((total+num)>100){ //倉(cāng)庫(kù)滿了,生產(chǎn)者等待
                            Bakery.class.wait();
                        }
                        //等待解除
                        total += num;
                        System.out.println(Thread.currentThread().getName()+"生產(chǎn)面包,庫(kù)存:"+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; //消費(fèi)者每次消費(fèi)1個(gè)面包
        @Override
        public void run() {
            try {
                while(true){ //一直消費(fèi)
                    synchronized (Bakery.class){
                        while((total-num)<0){ //倉(cāng)庫(kù)空了,消費(fèi)者等待
                            Bakery.class.wait();
                        }
                        //解除消費(fèi)者等待
                        total -= num;
                        System.out.println(Thread.currentThread().getName()+"消費(fèi)面包,庫(kù)存:"+total);
                        Thread.sleep(500);
                        Bakery.class.notifyAll(); //喚醒消費(fèi)
                    }
                    Thread.sleep(500);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

部分打印結(jié)果:

??四. 阻塞隊(duì)列

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

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

??隊(duì)列滿的時(shí)候,入隊(duì)列就堵塞等待(生產(chǎn)),直到有其他線程從隊(duì)列中取走元素
??隊(duì)列空的時(shí)候,出隊(duì)列就堵塞等待(消費(fèi)),直到有其他線程往隊(duì)列中插入元素 

??1. 生產(chǎn)者消費(fèi)者模型 

生產(chǎn)者消費(fèi)者模式就是通過(guò)一個(gè)容器來(lái)解決生產(chǎn)者和消費(fèi)者的強(qiáng)耦合問(wèn)題

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

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

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

??2. 標(biāo)準(zhǔn)庫(kù)中的阻塞隊(duì)列

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

??BlockingQueue 是一個(gè)接口. 真正實(shí)現(xiàn)的類是 LinkedBlockingQueue

??put 方法用于阻塞式的入隊(duì)列, take 用于阻塞式的出隊(duì)列

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

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

??3. 阻塞隊(duì)列的模擬實(shí)現(xiàn)

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

??當(dāng)隊(duì)列為空的時(shí)候,就不能取元素了,就進(jìn)入wait等待,當(dāng)有元素存放時(shí),喚醒

??當(dāng)隊(duì)列為滿的時(shí)候,就不能存元素了,就進(jìn)入wait等待,當(dāng)鈾元素取出時(shí),喚醒 

??‍???實(shí)現(xiàn)代碼:

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

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

相同點(diǎn):

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

不同點(diǎn):

??wait用于線程通信,讓線程在等待隊(duì)列中等待

??sleep讓線程阻塞一段時(shí)間,阻塞在阻塞隊(duì)列中

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

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

總結(jié)

到此這篇關(guān)于Java使用wait和notify實(shí)現(xiàn)線程之間的通信的文章就介紹到這了,更多相關(guān)Java wait和notify實(shí)現(xiàn)線程通信內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 基于FileNotFoundException問(wèn)題的解決

    基于FileNotFoundException問(wèn)題的解決

    這篇文章主要介紹了基于FileNotFoundException問(wèn)題的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • 淺談Java中return和finally的問(wèn)題

    淺談Java中return和finally的問(wèn)題

    在Java中當(dāng)try、finally語(yǔ)句中包含return語(yǔ)句時(shí),執(zhí)行情況到底是怎樣的,finally中的代碼是否執(zhí)行,大家眾說(shuō)紛紜,有的說(shuō)會(huì)執(zhí)行,有的說(shuō)不會(huì)執(zhí)行,到底哪種說(shuō)法正確,下面我們來(lái)詳細(xì)討論下
    2015-10-10
  • 使用Maven多模塊——打包指定模塊

    使用Maven多模塊——打包指定模塊

    這篇文章主要介紹了使用Maven多模塊——打包指定模塊問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-09-09
  • PowerJob的AbstractScriptProcessor實(shí)現(xiàn)類工作流程源碼解讀

    PowerJob的AbstractScriptProcessor實(shí)現(xiàn)類工作流程源碼解讀

    這篇文章主要為大家介紹了PowerJob的AbstractScriptProcessor源碼流程解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • java7鉆石語(yǔ)法知識(shí)點(diǎn)總結(jié)

    java7鉆石語(yǔ)法知識(shí)點(diǎn)總結(jié)

    在本篇文章里小編給大家整理的是關(guān)于java7鉆石語(yǔ)法的相關(guān)知識(shí)點(diǎn)內(nèi)容,有需要的朋友們參考下。
    2019-11-11
  • SpringBoot超詳細(xì)分析啟動(dòng)流程

    SpringBoot超詳細(xì)分析啟動(dòng)流程

    今天小編就為大家分享一篇關(guān)于SpringBoot整個(gè)啟動(dòng)過(guò)程的分析,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2022-07-07
  • spring如何使用xml裝配bean

    spring如何使用xml裝配bean

    這篇文章主要介紹了spring如何使用xml裝配bean,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • JBoss5.x下配置Log4j方法介紹

    JBoss5.x下配置Log4j方法介紹

    這篇文章主要介紹了JBoss5.x下配置Log4j方法介紹,小編覺(jué)得挺不錯(cuò)的,這里分享給大家,供需要的朋友參考。
    2017-10-10
  • Springboot項(xiàng)目?jī)?yōu)雅地處理日志的方法詳解

    Springboot項(xiàng)目?jī)?yōu)雅地處理日志的方法詳解

    這篇文章主要介紹了Springboot項(xiàng)目---優(yōu)雅地處理日志,本文通過(guò)實(shí)例圖文相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-07-07
  • Java8實(shí)現(xiàn)優(yōu)雅的獲取重復(fù)字符與次數(shù)

    Java8實(shí)現(xiàn)優(yōu)雅的獲取重復(fù)字符與次數(shù)

    這篇文章主要為大家詳細(xì)介紹了在Java8中,我們應(yīng)該如何進(jìn)行字符及字符串的去重,以及計(jì)算去重次數(shù),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解下
    2023-12-12

最新評(píng)論

星子县| 长子县| 塔城市| 巴东县| 长泰县| 凌海市| 衡水市| 义马市| 江津市| 乌审旗| 平定县| 嘉定区| 壤塘县| 达拉特旗| 特克斯县| 双峰县| 泗阳县| 偏关县| 大渡口区| 托里县| 赞皇县| 巴彦淖尔市| 北安市| 勃利县| 克拉玛依市| 修水县| 宝应县| 泌阳县| 九江县| 陆良县| 五华县| 蒲城县| 绥芬河市| 灵寿县| 石楼县| 同江市| 安乡县| 富平县| 台南县| 榆中县| 林芝县|