亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java多線程間的5種通信方式小結(jié)

 更新時(shí)間:2023年10月13日 08:42:45   作者:終有救贖  
有兩個(gè)線程,A 線程向一個(gè)集合里面依次添加元素“abc”字符串,一共添加十次,當(dāng)添加到第五次的時(shí)候,希望 B 線程能夠收到 A 線程的通知,然后 B 線程執(zhí)行相關(guān)的業(yè)務(wù)操作,本文介紹的5種通信方式都是基本這兩種模型來(lái)實(shí)現(xiàn)的,需要的朋友可以參考下

問(wèn)題

有兩個(gè)線程,A 線程向一個(gè)集合里面依次添加元素“abc”字符串,一共添加十次,當(dāng)添加到第五次的時(shí)候,希望 B 線程能夠收到 A 線程的通知,然后 B 線程執(zhí)行相關(guān)的業(yè)務(wù)操作。線程間通信的模型有兩種:共享內(nèi)存和消息傳遞,以下方式都是基本這兩種模型來(lái)實(shí)現(xiàn)的。

一、使用 volatile 關(guān)鍵字

基于 volatile 關(guān)鍵字來(lái)實(shí)現(xiàn)線程間相互通信是使用共享內(nèi)存的思想。大致意思就是多個(gè)線程同時(shí)監(jiān)聽(tīng)一個(gè)變量,當(dāng)這個(gè)變量發(fā)生變化的時(shí)候 ,線程能夠感知并執(zhí)行相應(yīng)的業(yè)務(wù)。這也是最簡(jiǎn)單的一種實(shí)現(xiàn)方式

public class TestSync {
    //定義共享變量來(lái)實(shí)現(xiàn)通信,它需要volatile修飾,否則線程不能及時(shí)感知
    static volatile boolean notice = false;
    public static void main(String[] args) {
        List<String>  list = new ArrayList<>();
        //線程A
        Thread threadA = new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                list.add("abc");
                System.out.println("線程A添加元素,此時(shí)list的size為:" + list.size());
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (list.size() == 5)
                    notice = true;
            }
        });
        //線程B
        Thread threadB = new Thread(() -> {
            while (true) {
                if (notice) {
                    System.out.println("線程B收到通知,開(kāi)始執(zhí)行自己的業(yè)務(wù)...");
                    break;
                }
            }
        });
        //需要先啟動(dòng)線程B
        threadB.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 再啟動(dòng)線程A
        threadA.start();
    }
}

二、使用 Object 類的 wait()/notify()

Object 類提供了線程間通信的方法:wait()、notify()、notifyAll(),它們是多線程通信的基礎(chǔ),而這種實(shí)現(xiàn)方式的思想自然是線程間通信。

注意:wait/notify 必須配合 synchronized 使用,wait 方法釋放鎖,notify 方法不釋放鎖。wait 是指在一個(gè)已經(jīng)進(jìn)入了同步鎖的線程內(nèi),讓自己暫時(shí)讓出同步鎖,以便其他正在等待此鎖的線程可以得到同步鎖并運(yùn)行,只有其他線程調(diào)用了notify(),notify并不釋放鎖,只是告訴調(diào)用過(guò)wait()的線程可以去參與獲得鎖的競(jìng)爭(zhēng)了,但不是馬上得到鎖,因?yàn)殒i還在別人手里,別人還沒(méi)釋放,調(diào)用 wait() 的一個(gè)或多個(gè)線程就會(huì)解除 wait 狀態(tài),重新參與競(jìng)爭(zhēng)對(duì)象鎖,程序如果可以再次得到鎖,就可以繼續(xù)向下運(yùn)行。

public class TestSync {
    public static void main(String[] args) {
        //定義一個(gè)鎖對(duì)象
        Object lock = new Object();
        List<String>  list = new ArrayList<>();
        // 線程A
        Thread threadA = new Thread(() -> {
            synchronized (lock) {
                for (int i = 1; i <= 10; i++) {
                    list.add("abc");
                    System.out.println("線程A添加元素,此時(shí)list的size為:" + list.size());
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if (list.size() == 5)
                        lock.notify();//喚醒B線程
                }
            }
        });
        //線程B
        Thread threadB = new Thread(() -> {
            while (true) {
                synchronized (lock) {
                    if (list.size() != 5) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println("線程B收到通知,開(kāi)始執(zhí)行自己的業(yè)務(wù)...");
                }
            }
        });
        //需要先啟動(dòng)線程B
        threadB.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //再啟動(dòng)線程A
        threadA.start();
    }
}

由輸出結(jié)果,在線程 A 發(fā)出 notify() 喚醒通知之后,依然是走完了自己線程的業(yè)務(wù)之后,線程 B 才開(kāi)始執(zhí)行,正好說(shuō)明 notify() 不釋放鎖,而 wait() 釋放鎖。

三、使用JUC工具類 CountDownLatch

jdk1.5 之后在java.util.concurrent包下提供了很多并發(fā)編程相關(guān)的工具類,簡(jiǎn)化了并發(fā)編程代碼的書(shū)寫,CountDownLatch 基于 AQS 框架,相當(dāng)于也是維護(hù)了一個(gè)線程間共享變量 state。

public class TestSync {
    public static void main(String[] args) {
        CountDownLatch countDownLatch = new CountDownLatch(1);
        List<String>  list = new ArrayList<>();
        //線程A
        Thread threadA = new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                list.add("abc");
                System.out.println("線程A添加元素,此時(shí)list的size為:" + list.size());
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (list.size() == 5)
                    countDownLatch.countDown();
            }
        });
        //線程B
        Thread threadB = new Thread(() -> {
            while (true) {
                if (list.size() != 5) {
                    try {
                        countDownLatch.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("線程B收到通知,開(kāi)始執(zhí)行自己的業(yè)務(wù)...");
                break;
            }
        });
        //需要先啟動(dòng)線程B
        threadB.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //再啟動(dòng)線程A
        threadA.start();
    }
}

四、使用 ReentrantLock 結(jié)合 Condition

public class TestSync {
    public static void main(String[] args) {
        ReentrantLock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        List<String> list = new ArrayList<>();
        //線程A
        Thread threadA = new Thread(() -> {
            lock.lock();
            for (int i = 1; i <= 10; i++) {
                list.add("abc");
                System.out.println("線程A添加元素,此時(shí)list的size為:" + list.size());
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (list.size() == 5)
                    condition.signal();
            }
            lock.unlock();
        });
        //線程B
        Thread threadB = new Thread(() -> {
            lock.lock();
            if (list.size() != 5) {
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("線程B收到通知,開(kāi)始執(zhí)行自己的業(yè)務(wù)...");
            lock.unlock();
        });
        threadB.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        threadA.start();
    }
}

這種方式使用起來(lái)并不是很好,代碼編寫復(fù)雜,而且線程 B 在被 A 喚醒之后由于沒(méi)有獲取鎖還是不能立即執(zhí)行,也就是說(shuō),A 在喚醒操作之后,并不釋放鎖。這種方法跟 Object 的 wait()/notify() 一樣。

五、基本 LockSupport 實(shí)現(xiàn)線程間的阻塞和喚醒

LockSupport 是一種非常靈活的實(shí)現(xiàn)線程間阻塞和喚醒的工具,使用它不用關(guān)注是等待線程先進(jìn)行還是喚醒線程先運(yùn)行,但是得知道線程的名字。

public class TestSync {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        //線程B
        final Thread threadB = new Thread(() -> {
            if (list.size() != 5) {
                LockSupport.park();
            }
            System.out.println("線程B收到通知,開(kāi)始執(zhí)行自己的業(yè)務(wù)...");
        });
        //線程A
        Thread threadA = new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                list.add("abc");
                System.out.println("線程A添加元素,此時(shí)list的size為:" + list.size());
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (list.size() == 5)
                    LockSupport.unpark(threadB);
            }
        });
        threadA.start();
        threadB.start();
    }
}

以上就是Java多線程間的5種通信方式小結(jié)的詳細(xì)內(nèi)容,更多關(guān)于Java多線程間通信方式的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java基礎(chǔ)知識(shí)之Java語(yǔ)言概述

    Java基礎(chǔ)知識(shí)之Java語(yǔ)言概述

    這篇文章主要介紹了Java基礎(chǔ)知識(shí)之Java語(yǔ)言概述,本文介紹了Java語(yǔ)言相關(guān)的基礎(chǔ)知識(shí)、歷史介紹、主要應(yīng)用方向等內(nèi)容,需要的朋友可以參考下
    2015-03-03
  • 透過(guò)Spring源碼查看Bean的命名轉(zhuǎn)換規(guī)則圖文詳解

    透過(guò)Spring源碼查看Bean的命名轉(zhuǎn)換規(guī)則圖文詳解

    Java Bean是一種 Java 編程語(yǔ)言編寫的可重用軟件組件,包括符合一定規(guī)范的Java 類、屬性和方法,用于描述和處理應(yīng)用程序中的數(shù)據(jù)對(duì)象,下面這篇文章主要給大家介紹了關(guān)于透過(guò)Spring源碼查看Bean的命名轉(zhuǎn)換規(guī)則的相關(guān)資料,需要的朋友可以參考下
    2023-06-06
  • JAVA 時(shí)間區(qū)間的字符串合法性驗(yàn)證

    JAVA 時(shí)間區(qū)間的字符串合法性驗(yàn)證

    需要對(duì)獲得的諸如08:30-11:00這樣的字符串進(jìn)行合法性驗(yàn)證,判定表示的時(shí)間區(qū)間是否合法,以及對(duì)高峰期時(shí)間的區(qū)間是否在總的時(shí)間區(qū)間內(nèi)部進(jìn)行判斷。
    2013-03-03
  • Java中byte、byte數(shù)組與int、long的轉(zhuǎn)換詳解

    Java中byte、byte數(shù)組與int、long的轉(zhuǎn)換詳解

    這篇文章分別給大家介紹了Java中byte和int之間的轉(zhuǎn)換、Java中 byte數(shù)組和int之間的轉(zhuǎn)換、Java中byte數(shù)組和long之間的轉(zhuǎn)換以及整理了整體工具類的源碼,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。
    2017-02-02
  • 原因分析IDEA導(dǎo)入Spring-kafka項(xiàng)目Gradle編譯失敗

    原因分析IDEA導(dǎo)入Spring-kafka項(xiàng)目Gradle編譯失敗

    這篇文章主要為大家介紹分析了IDEA導(dǎo)入Spring-kafka項(xiàng)目Gradle中編譯失敗原因及解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2022-02-02
  • swagger2和knife4j的詳細(xì)使用教程(入門級(jí))

    swagger2和knife4j的詳細(xì)使用教程(入門級(jí))

    最近項(xiàng)目中用到了Swagger2和knife4j作為接口文檔,所以下面這篇文章主要給大家介紹了關(guān)于swagger2和knife4j的詳細(xì)使用教程,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-09-09
  • Spring @Profile注解詳解

    Spring @Profile注解詳解

    這篇文章主要介紹了Spring @Profile注解詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • springboot簡(jiǎn)單接入websocket的操作方法

    springboot簡(jiǎn)單接入websocket的操作方法

    這篇文章主要介紹了springboot簡(jiǎn)單接入websocket的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-05-05
  • Java線程(Thread)四種停止方式代碼實(shí)例

    Java線程(Thread)四種停止方式代碼實(shí)例

    這篇文章主要介紹了Java線程(Thread)四種停止方式代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-03-03
  • 簡(jiǎn)單了解SpringBoot過(guò)濾器及使用方式

    簡(jiǎn)單了解SpringBoot過(guò)濾器及使用方式

    這篇文章主要介紹了簡(jiǎn)單了解SpringBoot過(guò)濾器及使用方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-04-04

最新評(píng)論