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

Java多線程中wait?notify等待喚醒機(jī)制詳解

 更新時(shí)間:2024年10月03日 10:35:06   作者:IYF.星辰  
這篇文章主要介紹了Java多線程中wait?notify等待喚醒機(jī)制,由于線程之間是搶占式執(zhí)行的,因此線程的執(zhí)行順序難以預(yù)知,但是實(shí)際開(kāi)發(fā)中有時(shí)候我們希望合理的協(xié)調(diào)多個(gè)線程之間的執(zhí)行先后順序,所以這里我們來(lái)介紹下等待喚醒機(jī)制,需要的朋友可以參考下

一.等待喚醒機(jī)制簡(jiǎn)介

由于線程之間是搶占式執(zhí)行的,因此線程的執(zhí)行順序難以預(yù)知。但是實(shí)際開(kāi)發(fā)中有時(shí)候我們希望合理的協(xié)調(diào)多個(gè)線程之間的執(zhí)行先后順序。為了完成協(xié)調(diào)的工作,這里主要設(shè)計(jì)三個(gè)方法:

  • wait() / wait(long timeout) : 讓當(dāng)前線程進(jìn)入等待狀態(tài)
  • notify() / notifyAll(): 喚醒在當(dāng)前對(duì)象上等待的線程

注意:wait,notify,notifyAll都是Object類(lèi)的方法

二.synchronized與wait()與notify()

  • synchronized的含義:

Java中每一個(gè)對(duì)象都可以成為一個(gè)監(jiān)視器(Monitor), 該Monitor由一個(gè)鎖(lock), 一個(gè)等待隊(duì)列(waiting queue ), 一個(gè)入口隊(duì)列( entry queue).

對(duì)于一個(gè)對(duì)象的方法, 如果沒(méi)有synchronized關(guān)鍵字, 該方法可以被任意數(shù)量的線程,在任意時(shí)刻調(diào)用。

對(duì)于添加了synchronized關(guān)鍵字的方法,任意時(shí)刻只能被唯一的一個(gè)獲得了對(duì)象實(shí)例鎖的線程調(diào)用。

synchronized用于實(shí)現(xiàn)多線程的同步操作

  • wait()功能:

wait(), notify(), notifyAll() 和 synchonized 需要搭配使用, 用于線程同步

wait()總是在一個(gè)循;環(huán)中被調(diào)用,掛起當(dāng)前線程來(lái)等待一個(gè)條件的成立。 Wait調(diào)用會(huì)一直等到其他線程調(diào)用notifyAll()時(shí)才返回。

當(dāng)一個(gè)線程在執(zhí)行synchronized 的方法內(nèi)部,調(diào)用了wait()后, 該線程會(huì)釋放該對(duì)象的鎖, 然后該線程會(huì)被添加到該對(duì)象的等待隊(duì)列中(waiting queue), 只要該線程在等待隊(duì)列中, 就會(huì)一直處于閑置狀態(tài), 不會(huì)被調(diào)度執(zhí)行。 要注意wait()方法會(huì)強(qiáng)迫線程先進(jìn)行釋放鎖操作,所以在調(diào)用wait()時(shí), 該線程必須已經(jīng)獲得鎖,否則會(huì)拋出異常。由于wait()在synchonized的方法內(nèi)部被執(zhí)行, 鎖一定已經(jīng)獲得, 就不會(huì)拋出異常了。

  • notify()的功能:

wait(), notify(), notifyAll() 和 synchonized 需要搭配使用, 用于線程同步

當(dāng)一個(gè)線程調(diào)用一個(gè)對(duì)象的notify()方法時(shí), 調(diào)度器會(huì)從所有處于該對(duì)象等待隊(duì)列(waiting queue)的線程中取出任意一個(gè)線程, 將其添加到入口隊(duì)列( entry queue) 中. 然后在入口隊(duì)列中的多個(gè)線程就會(huì)競(jìng)爭(zhēng)對(duì)象的鎖, 得到鎖的線程就可以繼續(xù)執(zhí)行。 如果等待隊(duì)列中(waiting queue)沒(méi)有線程, notify()方法不會(huì)產(chǎn)生任何作用

notifyAll() 和notify()工作機(jī)制一樣, 區(qū)別在于notifyAll()會(huì)將等待隊(duì)列(waiting queue)中所有的線程都添加到入口隊(duì)列中(entry queue)

三.等待喚醒機(jī)制案例

1.讓t1執(zhí)行wait()方法。

2.此時(shí)t2得到鎖,再讓t2執(zhí)行notify()方法釋放鎖。

3.此時(shí)t1得到鎖,t1會(huì)自動(dòng)從wait()方法之后的代碼,繼續(xù)執(zhí)行。

4.通過(guò)上述流程,我們就可以清楚的看到,wait()和notify()各自是怎么工作的了,也可以知道兩者是怎么配合的了。

import java.util.*;
public class Main {
    //創(chuàng)建一個(gè)將被兩個(gè)線程同時(shí)訪問(wèn)的共享對(duì)象
    public static Object loker = new Object();
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(()->{
            synchronized (loker){
                System.out.println("線程一初次獲得對(duì)象鎖,執(zhí)行過(guò)程中調(diào)用鎖對(duì)象的wait()方法~~");
                try {
                    loker.wait();
                    System.out.println("當(dāng)線程一被喚醒后,后面的代碼繼續(xù)執(zhí)行");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("線程一運(yùn)行結(jié)束");
        },"線程一");
        Thread t2 = new Thread(()->{
            synchronized (loker){
                System.out.println("線程二初次獲得對(duì)象鎖,執(zhí)行過(guò)程中調(diào)用鎖對(duì)象的notify()方法~~");
                loker.notify();
                System.out.println("喚醒線程一前,后面的代碼繼續(xù)執(zhí)行~~");
            }
            System.out.println("線程二結(jié)束");
        },"線程二");
        t1.start();
        //防止t2優(yōu)先獲得CPU執(zhí)行權(quán)而錯(cuò)過(guò)喚醒t1
        Thread.sleep(1000);
        t2.start();
    }
}

運(yùn)行結(jié)果(運(yùn)行流程也就是運(yùn)行的打印結(jié)果):

例題一

有三個(gè)線程,線程名稱(chēng)分別為:a,b,c。每個(gè)線程打印自己的名稱(chēng)。

需要讓他們同時(shí)啟動(dòng),并按 c,b,a的順序打印

代碼詳解:

import java.util.*;
public class Test {
    public static Object loker1 = new Object();
    public static Object loker2 = new Object();
    public static void main(String[] args) {
        System.out.println("打印順序如下:");
        Thread t1 = new Thread(()->{
            //為了防止線程A的喚醒沒(méi)有被線程B接受,這里先讓線程A睡一會(huì)
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+": C");
            synchronized (loker1){
                loker1.notify();
            }
        },"線程C");
        Thread t2 = new Thread(()->{
            synchronized (loker1){
                //等待線程A的喚醒
                try {
                    loker1.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName()+": B");
            //線程B喚醒線程C
            synchronized (loker2){
                loker2.notify();
            }
        },"線程B");
        Thread t3 = new Thread(()->{
            //線程C等待線程A的喚醒
            synchronized (loker2){
                try {
                    loker2.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName()+": A");
        },"線程A");
        //開(kāi)啟線程
        t1.start();
        t2.start();
        t3.start();
    }
}

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

例題二

有三個(gè)線程,分別只能打印A,B和C

要求按順序打印ABC,打印10次

輸出示例:

ABC

ABC

ABC

ABC

ABC

ABC

ABC

ABC

ABC

ABC

大致過(guò)程:

代碼詳解:

import java.util.*;
public class Demo {
    private static Object locker1 = new Object();
    private static Object locker2 = new Object();
    private static Object locker3 = new Object();
    public static void main(String[] args) throws InterruptedException {
        System.out.println("打印結(jié)果:");
        Thread t1 = new Thread(() -> {
            try {
                for (int i = 0; i < 10; i++) {
                    synchronized (locker1) {
                        locker1.wait();
                    }
                    System.out.print("A");
                    synchronized (locker2) {
                        locker2.notify();
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        Thread t2 = new Thread(() -> {
            try {
                for (int i = 0; i < 10; i++) {
                    synchronized (locker2) {
                        locker2.wait();
                    }
                    System.out.print("B");
                    synchronized (locker3) {
                        locker3.notify();
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        Thread t3 = new Thread(() -> {
            try {
                for (int i = 0; i < 10; i++) {
                    synchronized (locker3) {
                        locker3.wait();
                    }
                    System.out.println("C");
                    synchronized (locker1) {
                        locker1.notify();
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        t1.start();
        t2.start();
        t3.start();
        //讓三個(gè)線程都拿到鎖
        Thread.sleep(1000);
        // 從線程 t1 啟動(dòng)
        synchronized (locker1) {
            locker1.notify();
        }
    }
}

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

四.什么時(shí)候釋放鎖——wait()與notify()

由于等待一個(gè)鎖定線程只有在獲得這把鎖之后,才能恢復(fù)運(yùn)行,所以讓持有鎖的線程在不需要鎖的時(shí)候及時(shí)釋放鎖是很重要的。在以下情況下,持有鎖的線程會(huì)釋放鎖:

1.執(zhí)行完同步代碼塊。

2.在執(zhí)行同步代碼塊的過(guò)程中,遇到異常而導(dǎo)致線程終止。

3.在執(zhí)行同步代碼塊的過(guò)程中,執(zhí)行了鎖所屬對(duì)象的wait()方法,這個(gè)線程會(huì)釋放鎖,進(jìn)行對(duì)象的等待池。

除了以上情況外,只要持有鎖的對(duì)象還沒(méi)有執(zhí)行完同步代碼塊,就不會(huì)釋放鎖。因此在以下情況下,線程不會(huì)釋放鎖:

1.在執(zhí)行同步代碼塊的過(guò)程中,執(zhí)行了Thread.sleep()方法,當(dāng)前線程放棄CPU,開(kāi)始睡眠,在睡眠中不會(huì)釋放鎖。

2.在執(zhí)行同步代碼塊的過(guò)程中,執(zhí)行了Thread.yield()方法,當(dāng)前線程放棄CPU,但不會(huì)釋放鎖。

3.在執(zhí)行同步代碼塊的過(guò)程中,其他線程執(zhí)行了當(dāng)前對(duì)象的suspend()方法,當(dāng)前線程被暫停,但不會(huì)釋放鎖。但Thread類(lèi)的suspend()方法已經(jīng)被廢棄。

到此這篇關(guān)于Java多線程中wait notify等待喚醒機(jī)制詳解的文章就介紹到這了,更多相關(guān)Java等待喚醒機(jī)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot項(xiàng)目在IntelliJ IDEA中如何實(shí)現(xiàn)熱部署

    SpringBoot項(xiàng)目在IntelliJ IDEA中如何實(shí)現(xiàn)熱部署

    spring-boot-devtools是一個(gè)為開(kāi)發(fā)者服務(wù)的一個(gè)模塊,其中最重要的功能就是自動(dòng)應(yīng)用代碼更改到最新的App上面去。,這篇文章主要介紹了SpringBoot項(xiàng)目在IntelliJ IDEA中如何實(shí)現(xiàn)熱部署,感興趣的小伙伴們可以參考一下
    2018-07-07
  • 基于HashMap遍歷和使用方法(詳解)

    基于HashMap遍歷和使用方法(詳解)

    下面小編就為大家?guī)?lái)一篇基于HashMap遍歷和使用方法(詳解)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-08-08
  • java 對(duì)象的序列化和反序列化詳細(xì)介紹

    java 對(duì)象的序列化和反序列化詳細(xì)介紹

    這篇文章主要介紹了java 對(duì)象的序列化和反序列化的相關(guān)資料,需要的朋友可以參考下
    2016-10-10
  • Spring?Batch是什么

    Spring?Batch是什么

    SpringBatch是Spring框架的批量處理工具,支持大規(guī)模數(shù)據(jù)任務(wù)、錯(cuò)誤處理及監(jiān)控,在SpringBoot中通過(guò)Starter簡(jiǎn)化集成,結(jié)合分頁(yè)、Swagger、ActiveMQ等技術(shù),具備高性能和健壯性,適用于數(shù)據(jù)遷移、報(bào)表生成等場(chǎng)景,本文介紹Spring?Batch是什么的相關(guān)知識(shí),感興趣的朋友一起看看吧
    2025-07-07
  • Java中操作Word修訂功能的示例詳解

    Java中操作Word修訂功能的示例詳解

    Word的修訂功能是一種在文檔中進(jìn)行編輯和審閱的功能,它允許多個(gè)用戶(hù)對(duì)同一文檔進(jìn)行修改并跟蹤這些修改,以便進(jìn)行審查和接受或拒絕修改,下面我們就來(lái)學(xué)習(xí)一下Java中操作Word修訂功能的方法,需要的可以參考下
    2023-12-12
  • Java實(shí)現(xiàn)企業(yè)員工管理系統(tǒng)

    Java實(shí)現(xiàn)企業(yè)員工管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)企業(yè)員工管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • java實(shí)現(xiàn)合并兩個(gè)已經(jīng)排序的列表實(shí)例代碼

    java實(shí)現(xiàn)合并兩個(gè)已經(jīng)排序的列表實(shí)例代碼

    這篇文章主要介紹了java實(shí)現(xiàn)合并兩個(gè)已經(jīng)排序的列表實(shí)例代碼,有需要的朋友可以參考一下
    2013-12-12
  • java中串行流和并行流區(qū)別小結(jié)

    java中串行流和并行流區(qū)別小結(jié)

    串行流和并行流是兩種處理流操作的方式,串行流適用于小數(shù)據(jù)量且簡(jiǎn)單的數(shù)據(jù)處理,并行流則適用于大規(guī)模數(shù)據(jù)處理和需要并行計(jì)算的場(chǎng)景,能夠利用多線程并行處理,選擇使用哪種流取決于數(shù)據(jù)量大小、處理復(fù)雜度和是否需要并行計(jì)算,下面就來(lái)具體介紹一下兩者的區(qū)別
    2024-09-09
  • springboot實(shí)現(xiàn)發(fā)送QQ郵箱

    springboot實(shí)現(xiàn)發(fā)送QQ郵箱

    這篇文章主要為大家詳細(xì)介紹了springboot實(shí)現(xiàn)發(fā)送QQ郵箱,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • Springboot的Mapper中添加新的SQL語(yǔ)句方法詳解

    Springboot的Mapper中添加新的SQL語(yǔ)句方法詳解

    在如今的軟件開(kāi)發(fā)界,Spring Boot可是非常受歡迎的框架哦,尤其是在微服務(wù)和RESTful API的構(gòu)建上,下面給大家介紹我們?nèi)绾螢镾pring Boot項(xiàng)目中的Mapper添加新的SQL語(yǔ)句吧,感興趣的朋友一起看看吧
    2025-04-04

最新評(píng)論

湖口县| 崇州市| 曲阜市| 钦州市| 富宁县| 临泉县| 邯郸县| 富宁县| 调兵山市| 武乡县| 娄烦县| 隆回县| 上栗县| 攀枝花市| 香河县| 株洲县| 乌兰县| 邓州市| 吉安市| 桐梓县| 尚义县| 阳信县| 南部县| 永春县| 澜沧| 鄂托克前旗| 辽阳市| 新干县| 五寨县| 云阳县| 兴海县| 孟村| 甘肃省| 察雅县| 宜良县| 鸡泽县| 巧家县| 黄梅县| 三门峡市| 宜兰县| 白水县|