欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java多線程案例之阻塞隊(duì)列詳解

 更新時(shí)間:2022年10月18日 14:55:48   作者:Moon?Bay  
阻塞隊(duì)列是一種特殊的隊(duì)列.?也遵守?“先進(jìn)先出”?的原則.阻塞隊(duì)列能是一種線程安全的數(shù)據(jù)結(jié)構(gòu)。本文將通過一些示例為大家詳細(xì)講講阻塞隊(duì)列的原理與使用,感興趣的小伙伴可以學(xué)習(xí)一下

一.阻塞隊(duì)列介紹

1.1阻塞隊(duì)列特性

阻塞隊(duì)列特性:

一.安全性

二.產(chǎn)生阻塞效果

阻塞隊(duì)列是一種特殊的隊(duì)列. 也遵守 “先進(jìn)先出” 的原則.阻塞隊(duì)列能是一種線程安全的數(shù)據(jù)結(jié)構(gòu), 并且具有以下特性:

  • 當(dāng)隊(duì)列滿的時(shí)候, 繼續(xù)入隊(duì)列就會(huì)阻塞, 直到有其他線程從隊(duì)列中取走元素.
  • 當(dāng)隊(duì)列空的時(shí)候, 繼續(xù)出隊(duì)列也會(huì)阻塞, 直到有其他線程往隊(duì)列中插入元素.

阻塞隊(duì)列的一個(gè)典型應(yīng)用場(chǎng)景就是 “生產(chǎn)者消費(fèi)者模型”. 這是一種非常典型的開發(fā)模型.

1.2阻塞隊(duì)列的優(yōu)點(diǎn)

我們可以將阻塞隊(duì)列比做成"生產(chǎn)者"和"消費(fèi)者"的"交易平臺(tái)".

我們可以把這個(gè)模型來比做成"包餃子"

A 的作用是搟餃子皮,也就是"生產(chǎn)者"

B 的作用是包餃子,也就是"消費(fèi)者"

X 的作用一個(gè)當(dāng)作放搟好餃子皮的一個(gè)盤中,也就是阻塞隊(duì)列

這樣我們根據(jù)A,B,X可以想象以下場(chǎng)景

場(chǎng)景一:

當(dāng)A搟餃子皮的速度過快,X被A的桿好餃子皮放滿了,這樣A就需要停止搟餃子皮這一個(gè)操作,這時(shí)只能等待B來利用A提供的餃子皮包餃子后X所空出的空間,來給A提供生產(chǎn)的環(huán)境

場(chǎng)景二:

當(dāng)B包餃子的速度過快,X被B的包餃子所用的餃子皮用空,這樣B就需要停止包餃子這一個(gè)操作,這時(shí)只能等待A提供的餃子皮包餃子后X所存在餃子皮,來給B提供消費(fèi)的環(huán)境

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

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

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

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

比如在 “秒殺” 場(chǎng)景下, 服務(wù)器同一時(shí)刻可能會(huì)收到大量的支付請(qǐng)求. 如果直接處理這些支付請(qǐng)求,服務(wù)器可能扛不住(每個(gè)支付請(qǐng)求的處理都需要比較復(fù)雜的流程). 這個(gè)時(shí)候就可以把這些請(qǐng)求都放到一個(gè)阻塞隊(duì)列中, 然后再由消費(fèi)者線程慢慢的來處理每個(gè)支付請(qǐng)求.這樣做可以有效進(jìn)行 “削峰”, 防止服務(wù)器被突然到來的一波請(qǐng)求直接沖垮.

(2) 阻塞隊(duì)列也能使生產(chǎn)者和消費(fèi)者之間 解耦.

比如過年一家人一起包餃子. 一般都是有明確分工, 比如一個(gè)人負(fù)責(zé)搟餃子皮, 其他人負(fù)責(zé)包. 搟餃子皮的人就是 “生產(chǎn)者”, 包餃子的人就是 “消費(fèi)者”.搟餃子皮的人不關(guān)心包餃子的人是誰(能包就行, 無論是手工包, 借助工具, 還是機(jī)器包), 包餃子的人也不關(guān)心搟餃子皮的人是誰(有餃子皮就行, 無論是用搟面杖搟的, 還是拿罐頭瓶搟, 還是直接從超市買的).

2.1阻塞隊(duì)列對(duì)生產(chǎn)者的優(yōu)化

優(yōu)化一:能夠讓多個(gè)服務(wù)器程序之間更充分的解耦合:

如果不使用生產(chǎn)者和消費(fèi)者模型,此時(shí)A和B的耦合性比較強(qiáng),如果A線程出現(xiàn)一些狀況B就會(huì)掛,B線程出現(xiàn)一些狀況A就會(huì)掛,這時(shí)當(dāng)我們引入阻塞隊(duì)列后我們就可以將A,B線程分開,如果A,B線程掛了有阻塞隊(duì)列的存在下,是不會(huì)影響別的線程

優(yōu)化二:能夠?qū)τ谡?qǐng)求進(jìn)行"削峰填谷":

我們可以聯(lián)想到我國(guó)的三峽大壩,三峽大壩就相當(dāng)于阻塞隊(duì)列,當(dāng)我們遇到雨水大的季節(jié),我們就可以關(guān)閉三峽大壩,利用三峽大壩來存水;當(dāng)我們遇到干旱期,我們就可以打開三峽大壩的門,來放水解決干旱問題

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

3.1Java提供阻塞隊(duì)列實(shí)現(xiàn)的標(biāo)準(zhǔn)類

java官方也提供了阻塞隊(duì)列的標(biāo)準(zhǔn)類,主要有下面幾個(gè):

標(biāo)準(zhǔn)類說明
ArrayBlockingQueue一個(gè)由數(shù)組結(jié)構(gòu)組成的有界阻塞隊(duì)列
LinkedBlockingQueue一個(gè)由鏈表結(jié)構(gòu)組成的有界阻塞隊(duì)列
PriorityBlockingQueue一個(gè)支持優(yōu)先級(jí)排序的無界阻塞隊(duì)列
DelayQueue一個(gè)使用優(yōu)先級(jí)隊(duì)列實(shí)現(xiàn)的無界阻塞隊(duì)列
SynchronousQueue一個(gè)不存儲(chǔ)元素的阻塞隊(duì)列
LinkedTransferQueue一個(gè)由鏈表結(jié)構(gòu)組成的無界阻塞隊(duì)列
LinkedBlockingDeque一個(gè)由鏈表結(jié)構(gòu)組成的雙向阻塞隊(duì)列
BlockingQueue接口單向阻塞隊(duì)列實(shí)現(xiàn)了該接口
BlockingDeque接口雙向阻塞隊(duì)列實(shí)現(xiàn)了該接口

3.2Blockingqueue基本使用

在 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 等方法, 但是這些方法不帶有阻塞特性.

BlockingQueue<String> queue = new LinkedBlockingQueue<>();
// 入隊(duì)列
queue.put("abc");
// 出隊(duì)列. 如果沒有 put 直接 take, 就會(huì)阻塞.
String elem = queue.take();

四.阻塞隊(duì)列實(shí)現(xiàn)

4.1阻塞隊(duì)列的代碼實(shí)現(xiàn)

我們通過 “循環(huán)隊(duì)列” 的方式來實(shí)現(xiàn)

使用 synchronized 進(jìn)行加鎖控制.put 插入元素的時(shí)候, 判定如果隊(duì)列滿了, 就進(jìn)行 wait. (注意, 要在循環(huán)中進(jìn)行 wait. 被喚醒時(shí)不一定隊(duì)列就不滿了, 因?yàn)橥瑫r(shí)可能是喚醒了多個(gè)線程).take 取出元素的時(shí)候, 判定如果隊(duì)列為空, 就進(jìn)行 wait. (也是循環(huán) wait)

我們?cè)谠O(shè)計(jì)阻塞隊(duì)列的時(shí)候可以將隊(duì)列聯(lián)想成一個(gè)圓

class BlockingQueue{
    //隊(duì)列里存放的個(gè)數(shù)
   volatile private int size = 0;
    //隊(duì)列的頭節(jié)點(diǎn)
    private int head = 0;
    //隊(duì)列的尾節(jié)點(diǎn)
    private int prov = 0;
    //創(chuàng)建一個(gè)數(shù)組,我們來給這個(gè)數(shù)組的容量設(shè)置為100
    private int[] array = new int[100];
    //創(chuàng)建一個(gè)專業(yè)的鎖對(duì)象
    private Object object = new Object();
    //實(shí)現(xiàn)阻塞隊(duì)列中的put方法
    public void put(int value) throws InterruptedException {
        synchronized (object) {
            //當(dāng)數(shù)組已經(jīng)滿了
            if (size == array.length) {
                object.wait();
            } else {
                //我們可以優(yōu)化成prov = (prov + 1) % items.length
                array[prov] = value;
                prov ++;
               if (prov >= array.length) {
                   prov = 0;
               }
            }
            size++;
            object.notify();
        }
    }
    //實(shí)現(xiàn)阻塞隊(duì)列中的take方法
    public int take() throws InterruptedException {
        synchronized (object) {
            if (size == 0) {
                object.wait();
            }
            int x = array[head];
            head++;
            if (head >= array.length) {
                head = 0;
            }
            size--;
            object.notify();
            return x;
        }
    }
}

4.2阻塞隊(duì)列搭配生產(chǎn)者與消費(fèi)者的代碼實(shí)現(xiàn)

class BlockingQueue{
    //隊(duì)列里存放的個(gè)數(shù)
   volatile private int size = 0;
    //隊(duì)列的頭節(jié)點(diǎn)
    private int head = 0;
    //隊(duì)列的尾節(jié)點(diǎn)
    private int prov = 0;
    //創(chuàng)建一個(gè)數(shù)組,我們來給這個(gè)數(shù)組的容量設(shè)置為100
    private int[] array = new int[100];
    //創(chuàng)建一個(gè)專業(yè)的鎖對(duì)象
    private Object object = new Object();
    //實(shí)現(xiàn)阻塞隊(duì)列中的put方法
    public void put(int value) throws InterruptedException {
        synchronized (object) {
            //當(dāng)數(shù)組已經(jīng)滿了
            if (size == array.length) {
                object.wait();
            } else {
                //我們可以優(yōu)化成prov = (prov + 1) % items.length
                array[prov] = value;
                prov ++;
               if (prov >= array.length) {
                   prov = 0;
               }
            }
            size++;
            object.notify();
        }
    }
    //實(shí)現(xiàn)阻塞隊(duì)列中的take方法
    public int take() throws InterruptedException {
        synchronized (object) {
            if (size == 0) {
                object.wait();
            }
            int x = array[head];
            head++;
            if (head >= array.length) {
                head = 0;
            }
            size--;
            object.notify();
            return x;
        }
    }
}
public class Test {
    public static void main(String[] args) {
        BlockingQueue blockingQueue = new BlockingQueue();
        Thread thread1 = new Thread(()-> {
            while (true) {
                for (int i = 0; i < 100; i++) {
                    try {
                        blockingQueue.put(i);
                        System.out.println("生產(chǎn)了"+i);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        Thread thread2 = new Thread(()->{
                while (true) {
                    try {
                        int b = blockingQueue.take();
                        System.out.println("消耗了"+b);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
        });
        thread1.start();
        thread2.start();
    }
}

以上就是Java多線程案例之阻塞隊(duì)列詳解的詳細(xì)內(nèi)容,更多關(guān)于Java多線程阻塞隊(duì)列的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java?多線程并發(fā)ReentrantLock

    Java?多線程并發(fā)ReentrantLock

    這篇文章主要介紹了Java?多線程并發(fā)ReentrantLock,Java?提供了?ReentrantLock?可重入鎖來提供更豐富的能力和靈活性,感興趣的小伙伴可以參考一下
    2022-06-06
  • 詳解Spring中Bean后置處理器(BeanPostProcessor)的使用

    詳解Spring中Bean后置處理器(BeanPostProcessor)的使用

    BeanPostProcessor 接口也被稱為Bean后置處理器,通過該接口可以自定義調(diào)用初始化前后執(zhí)行的操作方法。本文將詳細(xì)講講它的使用,需要的可以參考一下
    2022-06-06
  • Java-lambda表達(dá)式入門看這一篇就夠了

    Java-lambda表達(dá)式入門看這一篇就夠了

    lambda表達(dá)式最簡(jiǎn)單的作用就是用于簡(jiǎn)化創(chuàng)建匿名內(nèi)部類對(duì)象,Lambda表達(dá)式是一個(gè)可傳遞的代碼塊,可以在以后執(zhí)行一次或多次,下面通過本文給大家介紹Java-lambda表達(dá)式入門教程,感興趣的朋友一起看看吧
    2021-05-05
  • Mybatis的TypeHandler加解密數(shù)據(jù)實(shí)現(xiàn)

    Mybatis的TypeHandler加解密數(shù)據(jù)實(shí)現(xiàn)

    在我們數(shù)據(jù)庫(kù)中有些時(shí)候會(huì)保存一些用戶的敏感信息,所以就需要對(duì)這些數(shù)據(jù)進(jìn)行加密,那么本文就介紹了Mybatis的TypeHandler加解密數(shù)據(jù)實(shí)現(xiàn),感興趣的可以了解一下
    2021-06-06
  • Java語法基礎(chǔ)之運(yùn)算符學(xué)習(xí)筆記分享

    Java語法基礎(chǔ)之運(yùn)算符學(xué)習(xí)筆記分享

    這篇文章主要為大家分享了Java語法基礎(chǔ)之運(yùn)算符學(xué)習(xí)筆記,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-09-09
  • 詳解JAVA中獲取文件MD5值的四種方法

    詳解JAVA中獲取文件MD5值的四種方法

    這篇文章主要介紹了JAVA中獲取文件MD5值的四種方法,獲取文件MD5值主要分為三個(gè)步驟,第一步獲取文件的byte信息,第二步通過MessageDigest類進(jìn)行MD5加密,第三步轉(zhuǎn)換成16進(jìn)制的MD5碼值,需要的朋友可以參考下
    2022-08-08
  • 詳解Java遞歸實(shí)現(xiàn)樹形結(jié)構(gòu)的兩種方式

    詳解Java遞歸實(shí)現(xiàn)樹形結(jié)構(gòu)的兩種方式

    在開發(fā)的過程中,很多業(yè)務(wù)場(chǎng)景需要一個(gè)樹形結(jié)構(gòu)的結(jié)果集進(jìn)行前端展示,也可以理解為是一個(gè)無限父子結(jié)構(gòu),常見的有報(bào)表指標(biāo)結(jié)構(gòu)、菜單結(jié)構(gòu)等,這篇文章主要介紹了Java遞歸實(shí)現(xiàn)樹形結(jié)構(gòu)的兩種方式,需要的朋友可以參考下
    2022-10-10
  • Spring Boot快速入門教程

    Spring Boot快速入門教程

    本篇文章主要介紹了Spring Boot快速入門教程,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-01-01
  • Java 數(shù)據(jù)結(jié)構(gòu)中二叉樹前中后序遍歷非遞歸的具體實(shí)現(xiàn)詳解

    Java 數(shù)據(jù)結(jié)構(gòu)中二叉樹前中后序遍歷非遞歸的具體實(shí)現(xiàn)詳解

    樹是一種重要的非線性數(shù)據(jù)結(jié)構(gòu),直觀地看,它是數(shù)據(jù)元素(在樹中稱為結(jié)點(diǎn))按分支關(guān)系組織起來的結(jié)構(gòu),很象自然界中的樹那樣。樹結(jié)構(gòu)在客觀世界中廣泛存在,如人類社會(huì)的族譜和各種社會(huì)組織機(jī)構(gòu)都可用樹形象表示
    2021-11-11
  • java實(shí)現(xiàn)計(jì)算器模板及源碼

    java實(shí)現(xiàn)計(jì)算器模板及源碼

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)計(jì)算器模板及源碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06

最新評(píng)論