国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Java線程間通信方式(3)

這篇具有很好參考價(jià)值的文章主要介紹了Java線程間通信方式(3)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

前文了解了線程通信方式中的CountDownLatch, Condition,ReentrantLock以及CyclicBarrier,接下來我們繼續(xù)了解其他的線程間通信方式。

Phaser

Phaser是JDK1.7中引入的一種功能上和CycliBarrier和CountDownLatch相似的同步工具,相對(duì)這兩者而言其用法更加靈活,同時(shí)Phaser也支持重用。

在Phaser中將需要協(xié)作完成的任務(wù)分成多個(gè)階段,每個(gè)階段的參與者可指定,參與者可以隨時(shí)注冊(cè)并參與到某個(gè)階段或者取消參與本階段。以選修課考試為例,說明Phaser的工作邏輯,假設(shè)現(xiàn)有選修課3門,政治,歷史,地理,各選修人數(shù)分別為20,10,10.按Phaser實(shí)現(xiàn)考試邏輯如下:

  • 第一階段考政治,總共應(yīng)有9名同學(xué)參加考試,在考試開始時(shí),8位同學(xué)開始答題,另外一位同學(xué)未到,考試中途,最后一位同學(xué)進(jìn)入,開始考試,所有同學(xué)答題完成后,政治考試結(jié)束
  • 第二階段考?xì)v史,總共9名同學(xué)參考考試,在考試結(jié)束前,3名同學(xué)棄考,則實(shí)際參與考試有6名同學(xué),所有同學(xué)答題完成后,歷史考試結(jié)束
  • 第三階段考地理,總共9名同學(xué)參與考試,中途無意外,所有同學(xué)答題完成后,地理考試結(jié)束

至此選修課考試的三個(gè)階段均完成,所以選修課考試這個(gè)任務(wù)結(jié)束,其中第一階段中晚到參考考試的同學(xué)說的就是參與者可以隨時(shí)注冊(cè)并參與到某個(gè)階段,第二階段中棄考的同學(xué)說的就是參與者可以隨時(shí)取消參與本階段,當(dāng)所有參與本階段的參與者均取消,則意味著該階段完成。

在Phaser中,針對(duì)一個(gè)階段而言,每一個(gè)參與者都被稱為一個(gè)party,可以通過構(gòu)造函數(shù)指定參與者數(shù)量,也可以通過register使parties(party的總和)自增,當(dāng)當(dāng)前階段的所有參與者等于parties的數(shù)量時(shí),此時(shí)phase自增1,進(jìn)入下一個(gè)階段,回調(diào)onAdvance方法

Phaser提供的核心函數(shù)如下所示:

函數(shù)名稱 描述 備注
register() 注冊(cè)一個(gè)party,使得parties+1 /
bulkRegister(int parties) 批量注冊(cè)party,使得parties變?yōu)橐延袀€(gè)數(shù)與傳入?yún)?shù)之和 /
arriveAndDeregister() 當(dāng)前任務(wù)已完成,使parties計(jì)數(shù)減1,不會(huì)形成阻塞 /
arriveAndAwaitAdvance() 已達(dá)到執(zhí)行點(diǎn),線程阻塞,等待下一階段喚醒繼續(xù)執(zhí)行 /
awaitAdvance(int phase) 參數(shù)是一個(gè)已完成的階段編號(hào),通常以已完成任務(wù)的arrive或者arriveAndDeregister函數(shù)的返回值作為取值,如果傳入?yún)?shù)的階段編號(hào)和當(dāng)前階段編號(hào)相同,則在此處等待,如果不同或者Phaser已經(jīng)是terminated狀態(tài),則立即返回 /
arrive() 達(dá)到當(dāng)前階段,不等待其他參與者到達(dá) /
arriveAndAwaitAdvance

以上述政治考試為例,學(xué)習(xí)Phaser基本使用

public static void main(String[] args) {
    // 創(chuàng)建Phaser
    Phaser phaser = new Phaser(){
        @Override
        protected boolean onAdvance(int phase, int registeredParties) {
            switch (phase) {
                case 0:
                    System.out.println("政治考試完成");
                    break;
                case 1:
                    System.out.println("歷史考試完成");
                    break;
                case 2:
                    System.out.println("地理考試完成");
                    break;
            }
            // 如果到達(dá)某一階段,Phaser中參與者為0,則會(huì)銷毀該P(yáng)haser
            return super.onAdvance(phase, registeredParties);
        }
    };
    
    IntStream.range(1,10).forEach(number->{
        phaser.register();
        Thread student= new Thread(()->{
            System.out.println("學(xué)生"+number+"arrive advance");
            // 等待其他線程,此時(shí)block
            phaser.arriveAndAwaitAdvance();
            System.out.println("學(xué)生"+number+"政治開始答題");
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("學(xué)生"+number+"政治交卷");
            // 考試完成,取消計(jì)數(shù),參與者減1
            phaser.arriveAndDeregister();
            System.out.println("Phaser is terminated :" +phaser.isTerminated());
        });
        student.start();
    });
    System.out.println("Phaser is terminated :" +phaser.isTerminated());
}

輸出如下:

Java線程間通信方式(3)

從上面可以看出,Phaser中通過arriveAndAwaitAdvance阻塞當(dāng)前線程,當(dāng)所有線程到達(dá)阻塞柵欄時(shí),喚醒等待線程繼續(xù)執(zhí)行,進(jìn)而達(dá)到線程間同步協(xié)作。

awaitAdvance

有時(shí)候,當(dāng)Phaser 在當(dāng)前階段結(jié)束時(shí),我們需要兜底做一些策略,比如說資源的釋放,狀態(tài)的檢查上報(bào)等,此時(shí)就需要用到awaitAdvance,awaitAdvance接受一個(gè)階段編號(hào),如果當(dāng)前階段編號(hào)和傳入的相等,則會(huì)進(jìn)入等待狀態(tài),等到所有參與者都到達(dá)該階段柵欄時(shí),被喚醒。實(shí)例代碼如下:

public static class ThreadA implements Runnable {
    private Phaser phaser;

    public ThreadA(Phaser phaser) {
        this.phaser = phaser;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " start ");


        phaser.arriveAndAwaitAdvance();

        System.out.println(Thread.currentThread().getName() + " end " );
    }
}

public static class ThreadB implements Runnable {
    private Phaser phaser;

    public ThreadB(Phaser phaser) {
        this.phaser = phaser;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " start " );

        phaser.arriveAndAwaitAdvance();

        System.out.println(Thread.currentThread().getName() + " end ");
    }
}

public static class ThreadC implements Runnable {
    private Phaser phaser;

    public ThreadC(Phaser phaser) {
        this.phaser = phaser;
    }

    @Override
    public void run() {
            System.out.println(Thread.currentThread().getName() + " start ");
            System.out.println(Thread.currentThread().getName() + " phaser.getPhase()=" + phaser.getPhase());
            phaser.awaitAdvance(0);
            System.out.println(Thread.currentThread().getName() + " end ");
    }
}

public static class ThreadD implements Runnable {
    private Phaser phaser;

    public ThreadD(Phaser phaser) {
        this.phaser = phaser;
    }

    @Override
    public void run() {
        try {
            System.out.println(Thread.currentThread().getName() + " begin sleep");

            Thread.sleep(5000);

            System.out.println(Thread.currentThread().getName() + " sleep completed ");
            phaser.arriveAndAwaitAdvance();

            System.out.println(Thread.currentThread().getName() + " end ");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public static void main(String[] args) {
    // 聲明Phaser
    Phaser phaser = new Phaser(3) {
        @Override
        protected boolean onAdvance(int phase, int registeredParties) {
            System.out.println("Phaser arrived at :"+phase);
            return super.onAdvance(phase, registeredParties);
        }
    };

    Thread t1 = new Thread(new ThreadA(phaser));
    Thread t2 = new Thread(new ThreadB(phaser));
    Thread t3 = new Thread(new ThreadC(phaser));
    Thread t4 = new Thread(new ThreadD(phaser));

    t1.setName("ThreadA");
    t2.setName("ThreadB");
    t3.setName("ThreadC");
    t4.setName("ThreadD");

    t1.start();
    t2.start();
    t3.start();
    t4.start();
}

如上代碼所示,聲明Phaser有三個(gè)參與者ThreadA,ThreadB,ThreadD,在三個(gè)參與者都執(zhí)行到arriveAndAwaitAdvance之前,ThreadC 阻塞等待,當(dāng)三個(gè)參與者都執(zhí)行到arriveAndAwaitAdvance后,回調(diào)onAdvance方法,此時(shí)被阻塞的參與者被喚醒執(zhí)行,之后ThreadC被喚醒繼續(xù)執(zhí)行,運(yùn)行結(jié)果如下:

Java線程間通信方式(3)

Exchanger

Exchanger用于兩個(gè)線程之間的通信,無論哪個(gè)線程先調(diào)用Exchanger,都會(huì)等待另外一個(gè)線程調(diào)用時(shí)進(jìn)行數(shù)據(jù)交換,示例代碼如下:

private static Exchanger<String> exchanger = new Exchanger<>();

public static void main(String[] args) {
    new Thread(()->{
        try {
            System.out.println(Thread.currentThread().getName()+" sleep start");
            Thread.sleep(10000);
            System.out.println(Thread.currentThread().getName()+" sleep end");
            System.out.println(Thread.currentThread().getName()+" send data to Exchanger");
            String aa = exchanger.exchange("data from Thread1");
            System.out.println(Thread.currentThread().getName() + "   "+aa);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }, "Thread1").start();

    new Thread(()->{
        try {
            System.out.println(Thread.currentThread().getName()+" send data to Exchanger");
            String bb = exchanger.exchange("data from Thread2");
            System.out.println(Thread.currentThread().getName() + "   "+bb);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }, "Thread2").start();
}

運(yùn)行輸出如下:

Java線程間通信方式(3)

總結(jié)

結(jié)合前文,我們一共學(xué)習(xí)了種線程間通信方式,主要有:

  1. Object.wait/Object.notify/Object.notifyAll + synchronized
  2. Semaphore(信號(hào)量)
  3. CountDownLatch
  4. CyclicBarrier
  5. Condition+ReentrantLock
  6. Phaser
  7. Exchanger

大家日常開發(fā)中可靈活使用,針對(duì)各通信方式比較見下表:文章來源地址http://www.zghlxwxcb.cn/news/detail-426974.html

通信方式 應(yīng)用場景 是否可重用 子任務(wù)異常處理 備注
Object.wait/Object.notify/Object.notifyAll + synchronized 大多數(shù)線程通信場景 依賴開發(fā)者維護(hù),在finally塊中完成釋放,避免死鎖 /
Semaphore(信號(hào)量) 通知喚醒類線程間通信場景 依賴開發(fā)者維護(hù),在finally塊中釋放信號(hào)量,避免死鎖 /
CountDownLatch 串行多線程運(yùn)行場景 不加處理的話,子任務(wù)發(fā)生異常導(dǎo)致退出,則所有等待的線程都會(huì)一致等待,直到超時(shí)時(shí)間來臨 /
CyclicBarrier 聚合類線程通信場景 不加處理的話,如果在所有線程都到達(dá)屏障陷入阻塞前,如果有線程發(fā)生異常導(dǎo)致未到達(dá)柵欄提前退出,則所有等待在柵欄都會(huì)以BrokenBarrierException或InterruptedException異常退出 /
Condition+ReentrantLock 大多數(shù)線程通信場景 依賴開發(fā)者維護(hù),在finally塊中完成釋放,避免死鎖 /
Phaser 適用CountDownLatch與CyclicBarrier組合場景 依賴開發(fā)者維護(hù),在finally塊中取消參與者,避免死鎖 /
Exchanger 線程間數(shù)據(jù)交換場景 依賴開發(fā)者維護(hù),確保兩個(gè)線程狀態(tài)正常,并行運(yùn)行 /

到了這里,關(guān)于Java線程間通信方式(3)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • [Java]線程生命周期與線程通信

    [Java]線程生命周期與線程通信

    【版權(quán)聲明】未經(jīng)博主同意,謝絕轉(zhuǎn)載?。ㄕ?qǐng)尊重原創(chuàng),博主保留追究權(quán)) https://www.cnblogs.com/cnb-yuchen/p/18162522 出自【進(jìn)步*于辰的博客】 線程生命周期與進(jìn)程有諸多相似,所以我們很容易將兩者關(guān)聯(lián)理解并混淆,一些細(xì)節(jié)之處確有許多不同,因?yàn)榫€程調(diào)度與進(jìn)程調(diào)度雖都由

    2024年04月27日
    瀏覽(20)
  • java 線程安全問題 三種線程同步方案 線程通信(了解)

    java 線程安全問題 三種線程同步方案 線程通信(了解)

    線程安全問題指的是,多個(gè)線程同時(shí)操作同一個(gè)共享資源的時(shí)候,可能會(huì)出現(xiàn)業(yè)務(wù)安全問題。 下面代碼演示上述問題,先定義一個(gè)共享的賬戶類: 在定義一個(gè)取錢的線程類 最后,再寫一個(gè)測(cè)試類,在測(cè)試類中創(chuàng)建兩個(gè)線程對(duì)象 某個(gè)執(zhí)行結(jié)果: 為了解決前面的線程安全問題,

    2024年02月09日
    瀏覽(16)
  • Java 進(jìn)階(12) 線程通信

    多個(gè)線程在處理同?個(gè)資源,但是處理的動(dòng)作(線程的任務(wù))卻不相同。 為什么要處理線程間通信 多個(gè)線程并發(fā)執(zhí)?時(shí), 在默認(rèn)情況下CPU是隨機(jī)切換線程的,當(dāng)我們需要多個(gè)線程來共同完成?件任務(wù),并且我們希望他們有規(guī)律的執(zhí)?, 那么多線程之間需要?些協(xié)調(diào)通信,以此

    2023年04月16日
    瀏覽(21)
  • 【Java】詳解多線程通信

    【Java】詳解多線程通信

    ?? 個(gè)人主頁: Dawn黎明開始 ?? 系列專欄: Java ? 每日一句:什么都不做,才會(huì)來不及 ?? 歡迎大家:關(guān)注 ??+ 點(diǎn)贊 ??+評(píng)論 ??+收藏?? 文章目錄 ??多線程通信 (1).??由來 (2).??成員方法? (3).??案例引入 (4).??代碼實(shí)現(xiàn) ? ? ? 現(xiàn)代社會(huì)崇尚合作精神,分工合作在日常

    2024年02月05日
    瀏覽(21)
  • 深入理解Java線程間通信

    合理的使用Java多線程可以更好地利用服務(wù)器資源。一般來講,線程內(nèi)部有自己私有的線程上下文,互不干擾。但是當(dāng)我們需要多個(gè)線程之間相互協(xié)作的時(shí)候,就需要我們掌握J(rèn)ava線程的通信方式。本文將介紹Java線程之間的幾種通信原理。 在Java中,鎖的概念都是基于對(duì)象的,

    2024年02月09日
    瀏覽(25)
  • Java多線程 - Java創(chuàng)建線程的4種方式

    Java多線程 - Java創(chuàng)建線程的4種方式

    1. Java創(chuàng)建線程有哪幾種方式? 一個(gè)線程在Java中使用一個(gè)Thread實(shí)例來描述。Thread類是Java語言的一個(gè)重要的基礎(chǔ)類,位于java.lang包中。Thread類有不少非常重要的屬性和方法,用于存儲(chǔ)和操作線程的描述信息。 Thread類的構(gòu)造方法: 1.1 線程創(chuàng)建方法一:繼承Thread類創(chuàng)建線程類 (

    2023年04月08日
    瀏覽(19)
  • Java——》線程間是如何通信的

    Java——》線程間是如何通信的

    推薦鏈接: ????總結(jié)——》【Java】 ????總結(jié)——》【Mysql】 ????總結(jié)——》【Redis】 ????總結(jié)——》【Kafka】 ????總結(jié)——》【Spring】 ????總結(jié)——》【SpringBoot】 ????總結(jié)——》【MyBatis、MyBatis-Plus】 ????總結(jié)——》【Linux】 ????總結(jié)——》【MongoDB】 ???

    2024年02月09日
    瀏覽(19)
  • Java多線程(1)---多線程認(rèn)識(shí)、四種創(chuàng)建方式以及線程狀態(tài)

    Java多線程(1)---多線程認(rèn)識(shí)、四種創(chuàng)建方式以及線程狀態(tài)

    目錄 前言 一.Java的多線程 1.1多線程的認(rèn)識(shí)? 1.2Java多線程的創(chuàng)建方式 1.3Java多線程的生命周期 1.4Java多線程的執(zhí)行機(jī)制 二.創(chuàng)建多線程的四種方式 2.1繼承Thread類 ?創(chuàng)建線程? ?Thread的構(gòu)造方法和常見屬性 ?2.2.實(shí)現(xiàn)Runnable接口 ?創(chuàng)建線程 ?使用lambda表達(dá)式創(chuàng)建 2.3實(shí)現(xiàn)Callable接口

    2024年02月14日
    瀏覽(24)
  • 線程方法接收參數(shù)示例,Java的兩種線程實(shí)現(xiàn)方式區(qū)別

    總所周知,Java實(shí)現(xiàn)多線程有兩種方式,分別是繼承Thread類和實(shí)現(xiàn)Runable接口,那么它們的區(qū)別是什么? 繼承 Thread 類: 通過繼承 Thread 類,你可以創(chuàng)建一個(gè)直接表示線程的類。你可以覆蓋 Thread 類中的 run 方法來定義線程的邏輯。當(dāng)調(diào)用 start 方法啟動(dòng)線程時(shí),會(huì)執(zhí)行該類中的

    2024年02月11日
    瀏覽(54)
  • 【面試精講】Java線程6種狀態(tài)和工作原理詳解,Java創(chuàng)建線程的4種方式

    【面試精講】Java線程6種狀態(tài)和工作原理詳解,Java創(chuàng)建線程的4種方式

    Java線程6種狀態(tài)和工作原理詳解,Java創(chuàng)建線程的4種方式 一、Java線程的六種狀態(tài) 二、Java線程是如何工作的? 三、BLOCKED 和 WAITING 的區(qū)別 四、start() 和 run() 源碼分析 五、Java創(chuàng)建線程的所有方式和代碼詳解 1. 繼承Thread類 2. 實(shí)現(xiàn)Runnable接口 3. 實(shí)現(xiàn)Callable接口與FutureTask 4. 使用線

    2024年03月13日
    瀏覽(22)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包