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

Java線程通信及線程虛假喚醒知識(shí)總結(jié)

 更新時(shí)間:2021年06月28日 10:27:26   作者:少年做自己的英雄  
今天給大家?guī)?lái)的是關(guān)于Java線程的相關(guān)知識(shí),文章圍繞著Java線程通信及線程虛假喚醒的知識(shí)展開(kāi),文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下

線程通信

線程在內(nèi)部運(yùn)行時(shí),線程調(diào)度具有一定的透明性,程序通常無(wú)法控制線程的輪換執(zhí)行。但Java本身提供了一些機(jī)制來(lái)保證線程協(xié)調(diào)運(yùn)行。

假設(shè)目前系統(tǒng)中有兩個(gè)線程,分別代表存款和取錢(qián)。當(dāng)錢(qián)存進(jìn)去,立馬就取出來(lái)挪入指定賬戶。這涉及到線程間的協(xié)作,使用到Object類(lèi)提供的wait()、notify()、notifyAll()三個(gè)方法,其不屬于Thread類(lèi),而屬于Object,而這三個(gè)方法必須由監(jiān)視器對(duì)象來(lái)調(diào)用:

  • synchronized修飾的方法,因?yàn)樵擃?lèi)的默認(rèn)實(shí)例(this)就是同步監(jiān)視器,因此可以在同步方法中直接調(diào)用
  • synchronized修飾的同步代碼塊,同步監(jiān)視器是synchronized括號(hào)里的對(duì)象,因此必須使用該對(duì)象來(lái)調(diào)用

三個(gè)方法解釋如下:

  • wait():當(dāng)前線程等待,釋放當(dāng)前對(duì)象鎖,讓出CPU,直到其他線程使用notify或者notifyAll喚醒該線程
  • notify():?jiǎn)拘言诖送奖O(jiān)視器上等待的單個(gè)線程,若存在多個(gè)線程,則隨機(jī)喚醒一個(gè)。執(zhí)行了notify不會(huì)馬上釋放鎖,只有完全退出synchronized代碼塊或者中途遇到wait,呈wait狀態(tài)的線程才可以去爭(zhēng)取該對(duì)象鎖
  • notifyAll():?jiǎn)拘言诖送奖O(jiān)視器上的所有線程,同上。

現(xiàn)在用兩個(gè)同步方法分別代表存錢(qián)取錢(qián)

  • 當(dāng)余額為0時(shí),進(jìn)入存錢(qián)流程,執(zhí)行存錢(qián)操作后,喚醒取錢(qián)線程
  • 當(dāng)余額為0時(shí),進(jìn)入取錢(qián)流程,發(fā)現(xiàn)num==0,進(jìn)入阻塞狀態(tài),等待被喚醒
/**
     * 存一塊錢(qián)
     *
     * @throws InterruptedException
     */
    public synchronized void increase() throws InterruptedException {
        // 當(dāng)余額為1,說(shuō)明已經(jīng)存過(guò)錢(qián),等待取錢(qián)。存錢(qián)方法阻塞
        if (num == 1) {
            this.wait();
        }
        // 執(zhí)行存錢(qián)操作
        num++;
        System.out.println(Thread.currentThread().getName() + ":num=" + num);
        // 喚醒其他線程
        this.notifyAll();
    }
 
    /**
     * 取一塊錢(qián)
     *
     * @throws InterruptedException
     */
    public synchronized void decrease() throws InterruptedException {
        // 當(dāng)余額為0,說(shuō)明已經(jīng)取過(guò)錢(qián),等待存錢(qián)。取錢(qián)方法阻塞
        if (num == 0) {
            this.wait();
        }
        num--;
        System.out.println(Thread.currentThread().getName() + ":num=" + num);
        this.notifyAll();
    }

調(diào)用方法:

private int num = 0;
 
    public static void main(String[] args) {
        Test test = new Test();
 
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    test.increase();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "存錢(qián)").start();
 
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    test.decrease();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "取錢(qián)").start();
    }

結(jié)果沒(méi)有什么問(wèn)題 

線程虛假喚醒

上述線程通信看起來(lái)似乎沒(méi)有什么問(wèn)題,但若此時(shí)將存錢(qián)和取錢(qián)的人數(shù)各增加1,再看運(yùn)行結(jié)果

private int num = 0;
 
    public static void main(String[] args) {
        Test test = new Test();
 
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    test.increase();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "存錢(qián)1").start();
 
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    test.decrease();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "取錢(qián)1").start();
 
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    test.increase();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "存錢(qián)2").start();
 
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    test.decrease();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "取錢(qián)2").start();
    }

產(chǎn)生的結(jié)果已經(jīng)不是最初的只有0和1

造成這個(gè)結(jié)果的原因就是線程間的虛假喚醒

由于目前分別有多個(gè)取款和存款線程。假設(shè)其中一個(gè)存款線程執(zhí)行完畢,并使用wait釋放同步監(jiān)視器鎖定,那其余多個(gè)取款線程將同時(shí)被喚醒,此時(shí)余額為1,如果有10個(gè)同時(shí)取錢(qián),那余額會(huì)變?yōu)?9,造成結(jié)果錯(cuò)誤。

因此,每次線程從wait中被喚醒,都必須再次測(cè)試是否符合喚醒條件,如果不符合那就繼續(xù)等待。

由于多個(gè)線程被同時(shí)喚醒,在if(xxxx){wait();}處 if判斷只會(huì)執(zhí)行一次,當(dāng)下一個(gè)被喚醒的線程過(guò)來(lái)時(shí),由于if已經(jīng)判斷過(guò),則直接從wait后面的語(yǔ)句繼續(xù)執(zhí)行,因此將if換成while可解決該問(wèn)題,下次被喚醒的線程過(guò)來(lái),while重新判斷一下,發(fā)現(xiàn)上一個(gè)被喚醒的線程已經(jīng)拿到鎖,因此這個(gè)被虛假喚醒的線程將繼續(xù)等待鎖。

 /**
     * 存一塊錢(qián)
     *
     * @throws InterruptedException
     */
    public synchronized void increase() throws InterruptedException {
        while (num == 1) {// 防止每次進(jìn)來(lái)的喚醒線程只判斷一次造成虛假喚醒,替換成while
            this.wait();
        }
        num++;
        System.out.println(Thread.currentThread().getName() + ":num=" + num);
        this.notifyAll();
    }
 
    /**
     * 取一塊錢(qián)
     *
     * @throws InterruptedException
     */
    public synchronized void decrease() throws InterruptedException {
        while (num == 0) {
            this.wait();
        }
        num--;
        System.out.println(Thread.currentThread().getName() + ":num=" + num);
        this.notifyAll();
    }

再次運(yùn)行,結(jié)果正常:

到此這篇關(guān)于Java線程通信及線程虛假喚醒知識(shí)總結(jié)的文章就介紹到這了,更多相關(guān)Java線程通信及線程虛假喚醒內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java中的數(shù)組排序方式(快速排序、冒泡排序、選擇排序)

    Java中的數(shù)組排序方式(快速排序、冒泡排序、選擇排序)

    這篇文章主要介紹了Java中的數(shù)組排序方式(快速排序、冒泡排序、選擇排序),需要的朋友可以參考下
    2014-02-02
  • java字符緩沖流面試精講

    java字符緩沖流面試精講

    這篇文章主要為大家介紹了java中字符緩沖流面試精講,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10
  • Redisson分布式鎖的源碼解讀分享

    Redisson分布式鎖的源碼解讀分享

    Redisson是一個(gè)在Redis的基礎(chǔ)上實(shí)現(xiàn)的Java駐內(nèi)存數(shù)據(jù)網(wǎng)格(In-Memory?Data?Grid)。Redisson有一樣功能是可重入的分布式鎖。本文來(lái)討論一下這個(gè)功能的特點(diǎn)以及源碼分析
    2022-11-11
  • SpringMVC超詳細(xì)講解視圖和視圖解析器

    SpringMVC超詳細(xì)講解視圖和視圖解析器

    這篇文章主要介紹了springMVC中的視圖與視圖解析器,springMVC視圖的種類(lèi)很多,默認(rèn)有轉(zhuǎn)發(fā)視圖和重定向視圖,本文就每一種視圖給大家詳細(xì)介紹,需要的朋友可以參考下
    2022-06-06
  • Java Socket報(bào)錯(cuò)打開(kāi)文件過(guò)多的問(wèn)題

    Java Socket報(bào)錯(cuò)打開(kāi)文件過(guò)多的問(wèn)題

    這篇文章主要介紹了Java Socket報(bào)錯(cuò)打開(kāi)文件過(guò)多的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • java面向?qū)ο缶幊讨匾拍罾^承和多態(tài)示例解析

    java面向?qū)ο缶幊讨匾拍罾^承和多態(tài)示例解析

    這篇文章主要為大家介紹了java面向?qū)ο缶幊痰膬蓚€(gè)重要概念繼承和多態(tài)示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • Java利用MD5加鹽實(shí)現(xiàn)對(duì)密碼進(jìn)行加密處理

    Java利用MD5加鹽實(shí)現(xiàn)對(duì)密碼進(jìn)行加密處理

    在開(kāi)發(fā)的時(shí)候,有一些敏感信息是不能直接通過(guò)明白直接保存到數(shù)據(jù)庫(kù)的。最經(jīng)典的就是密碼了。如果直接把密碼以明文的形式入庫(kù),不僅會(huì)泄露用戶的隱私,對(duì)系統(tǒng)也是極其的不厲。本文就來(lái)和大家介紹一下如何對(duì)密碼進(jìn)行加密處理,感興趣的可以了解一下
    2023-02-02
  • 微信公眾平臺(tái)(測(cè)試接口)準(zhǔn)備工作

    微信公眾平臺(tái)(測(cè)試接口)準(zhǔn)備工作

    想要微信開(kāi)發(fā),首先要有個(gè)服務(wù)器,但是自己沒(méi)有。這時(shí)候可以用花生殼,將內(nèi)網(wǎng)映射到公網(wǎng)上,這樣就可以在公網(wǎng)訪問(wèn)自己的網(wǎng)站了。
    2016-05-05
  • springboot如何關(guān)掉tomcat容器

    springboot如何關(guān)掉tomcat容器

    這篇文章主要介紹了springboot如何關(guān)掉tomcat容器,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • Java實(shí)現(xiàn)的圖片高質(zhì)量縮放類(lèi)定義與用法示例

    Java實(shí)現(xiàn)的圖片高質(zhì)量縮放類(lèi)定義與用法示例

    這篇文章主要介紹了Java實(shí)現(xiàn)的圖片高質(zhì)量縮放類(lèi)定義與用法,涉及java針對(duì)圖片的運(yùn)算與轉(zhuǎn)換等相關(guān)操作技巧,需要的朋友可以參考下
    2017-11-11

最新評(píng)論

祁东县| 合作市| 永顺县| 山东| 乌兰察布市| 洛浦县| 淅川县| 微博| 澜沧| 基隆市| 徐州市| 奇台县| 新巴尔虎左旗| 阳谷县| 凉城县| 通榆县| 安塞县| 航空| 如皋市| 屯留县| 庆元县| 勐海县| 溧水县| 乐都县| 广灵县| 宝丰县| 漳平市| 新绛县| 师宗县| 莫力| 西乌珠穆沁旗| 安化县| 赫章县| 龙陵县| 湟中县| 平遥县| 上高县| 乃东县| 密山市| 福建省| 南皮县|