溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

ArrayBlockQueue函數及應用場景是什么

發(fā)布時間:2023-03-30 11:19:07 來源:億速云 閱讀:83 作者:iii 欄目:開發(fā)技術

今天小編給大家分享一下ArrayBlockQueue函數及應用場景是什么的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

    隊列在生活中隨處可見,醫(yī)院繳費需要排隊、做核酸需要排隊、汽車等紅綠燈需要排隊等等。

    ArrayBlockQueue函數及應用場景是什么

    隊列是一個按照先來到就排在前面,后來到排在后面的數據結構,并且出隊的時候也是按照先來到先出隊。使用數組和鏈表進行實現。通常用于協(xié)調任務的執(zhí)行和數據的交換。

    介紹

    ArrayBlockingQueue 是一個有界阻塞隊列,有界指的是隊列存在一個最大容量;阻塞指的是如果隊列已經滿了,想要往隊列繼續(xù)添加元素的話,那么這個操作將會被暫停,直到隊列中有空位才會繼續(xù)完成添加操作。如果隊列已經為空,想要從隊列中獲取元素,那么這個操作將會被暫停,直接隊列中存在元素才會繼續(xù)完成獲取操作。

    它具有線程安全、性能好、公平鎖選項的特點:

    • 線程安全:使用鎖和條件變量實現線程安全,無需額外的同步措施。

    • 阻塞操作:當隊列滿時,插入操作阻塞;當隊列空時,刪除操作阻塞。這有助于避免忙等待和減少無意義的資源消耗。

    • 公平鎖選項:支持是否使用公平鎖。避免鎖饑餓。

    • 高性能:基于數組實現,內存連續(xù)分配,訪問性能較高。

    但是同時也存在不靈活、無法支撐高并發(fā)的缺點

    • 有界性:隊列的容量固定,不可動態(tài)改變。因此在創(chuàng)建時分配多大容量將成為關鍵,分配過多會造成資源浪費,分配過少會造成競爭激烈。

    • 鎖競爭:在高并發(fā)情況下,鎖競爭可能會導致性能下降。

    實現原理

    ArrayBlockingQueue 內部使用數組作為元素的存儲結構。

    執(zhí)行存取操作時,都必須先獲取鎖,才可以執(zhí)行存取操作,這就保證ArrayBlockingQueue 是線程安全。

    ArrayBlockingQueue 通過兩個 Condition 條件隊列,一個 notFull 條件,一個 notEmpty 條件。在對隊列進行插入元素操作時,判斷當前隊列已經滿,則通過 notFull 條件將線程阻塞,直到其他線程通知該線程隊列可以繼續(xù)插入元素。在對隊列進行移除元素操作時,判斷當前隊列已經空,則通過 notEmpty 條件阻塞線程,直到其他線程通過該線程可以繼續(xù)獲取元素。

    這樣保證線程的存取操作不會出現錯誤。避免隊列在滿時,丟棄插入的元素;也避免在隊列空時取到一個 null 值。

    構造函數

    public ArrayBlockingQueue(int capacity, boolean fair) {
        if (capacity <= 0)
            throw new IllegalArgumentException();
        this.items = new Object[capacity];
        lock = new ReentrantLock(fair);
        notEmpty = lock.newCondition();
        notFull =  lock.newCondition();
    }

    構造函數中,需要指定隊列的容量和是否使用公平鎖。并且創(chuàng)建了兩個 Condition 條件隊列,分別命名為 notEmpty 和 notFull,這兩個條件隊列是實現阻塞的關鍵。

    通過構造函數我們可以知道為什么它叫有界:因為創(chuàng)建數組時,需要指定數組的容量,并且數組容量不能在運行中動態(tài)擴大。所以隊列的容量是有邊界的,不是無限擴張的。

    插入函數

    public void put(E e) throws InterruptedException {
        Objects.requireNonNull(e);
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            while (count == items.length)
                notFull.await();
            enqueue(e);
        } finally {
            lock.unlock();
        }
    }
    • 獲取鎖

    • 判斷當前隊列是否已經滿了

    • 如果隊列1已經滿了,調用 notFull 條件隊列的 await() 方法,將該線程阻塞,暫停該線程的插入操作。避免內部溢出的問題。

    • 如果沒有滿,則直接調用入隊函數 enqueue 插入到隊列末尾。

    • 解鎖

    ArrayBlockQueue函數及應用場景是什么

    獲取函數

    public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            while (count == 0)
                notEmpty.await();
            return dequeue();
        } finally {
            lock.unlock();
        }
    }
    • 獲取鎖

    • 判斷當前隊列是否為空

    • 如果隊列沒有元素,調用 notEmpty 條件隊列的 await() 方法,將該線程阻塞,暫停該線程的獲取操作。避免獲取元素出錯。

    • 如果不為空,則直接調用出隊函數 dequeue 移除隊列第一個元素,并返回給客戶端。

    • 釋放鎖

    ArrayBlockQueue函數及應用場景是什么

    入隊函數

    private void enqueue(E e) {
        final Object[] items = this.items;
        items[putIndex] = e;
        if (++putIndex == items.length) putIndex = 0;
        count++;
        notEmpty.signal();
    }

    將元素插入到隊列的尾部,在完成插入操作之后會調用 notEmpty 對象的 signal 方法,告訴 notEmpty 阻塞隊列,現在隊列中已經有元素,之前因為隊列沒有元素而被阻塞的線程,現在可以來獲取元素了。

    ArrayBlockQueue函數及應用場景是什么

    內部維護一個 putIndex,用于表示下一個將要插入元素的坐標。當 putIndex 等于數組長度時,將會重置為 0。putIndex 是一個從 0 - length 循環(huán)使用的坐標。

    維護一個 count 變量,用于表示隊列中存在多少元素,在存入的時候增加,在取出的時候減少。

    ArrayBlockQueue函數及應用場景是什么

    出隊函數

    private E dequeue() {
        final Object[] items = this.items;
        @SuppressWarnings("unchecked")
        E e = (E) items[takeIndex];
        items[takeIndex] = null;
        if (++takeIndex == items.length) takeIndex = 0;
        count--;
        if (itrs != null)
            itrs.elementDequeued();
        notFull.signal();
        return e;
    }

    將隊列的第一個元素移除,并返回給客戶端。在完成移除操作之后會調用 notFull 對象的 signal 方法,告訴 notFull 阻塞隊列,現在隊列中已經有空位了,之前因為隊列沒有空位而被阻塞的線程,現在可以繼續(xù)插入元素。

    ArrayBlockQueue函數及應用場景是什么

    內部維護一個 takeIndex,用于表示下一個可以獲取元素的坐標。當 takeIndex 等于數組長度時,將會重置為 0。takeIndex 是一個從 0 至數組長度之間循環(huán)使用的坐標。

    ArrayBlockQueue函數及應用場景是什么

    應用場景

    適用場景

    ArrayBlockingQueue 適用于多個線程之間需要共享數據、協(xié)調任務執(zhí)行的場景。因此可以總結出以下幾個應用場景:

    • 線程池:線程池是一個常見的并發(fā)編程模型,它通過線程池中的線程執(zhí)行任務。并且可以重復使用這些線程。在線程池中,可以使用 ArrayBlockingQueue 來存儲需要執(zhí)行的任務,以此控制任務數量和執(zhí)行順序。當線程池中的線程執(zhí)行完任務之后,可以從 ArrayBlockingQueue 中取出下一個任務執(zhí)行。

    • 生產者-消費者:在生產者-消費者模型中,生產者負責生產數據,消費者負責對數據進行處理。在這種模式下,ArrayBlockingQueue 可以作為生產者與消費者之間的數據通道,保證線程安全和數據正確。

    實際應用場景

    • Apache Tomcat Apache Tomcat 是一個流行的 Java Web 應用服務器,它使用 ArrayBlockingQueue 來實現內部的請求隊列。當請求到達 Tomcat 時,它們被放入一個 ArrayBlockingQueue 中,并由工作線程從隊列中取出并處理請求。

    • Netty Netty 是一個高性能的網絡編程框架,它使用 ArrayBlockingQueue 來實現內部的事件隊列。當有新的網絡事件到達時,它們被放入一個 ArrayBlockingQueue 中,并由 IO 線程從隊列中取出并處理事件。

    以上就是“ArrayBlockQueue函數及應用場景是什么”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業(yè)資訊頻道。

    向AI問一下細節(jié)

    免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI