JUC編程:自定義實現有界阻塞隊列

看了各種博文,覺得還是自己看看源碼,理解完後自己實現一遍最好

1:BlockingQueue繼承關係

  java.util.concurrent 包裏的 BlockingQueue是一個接口, 繼承Queue接口,Queue接口繼承 Collection

BlockingQueue :不接受 null 元素。試圖 add、put 或 offer 一個 null 元素時,某些實現會拋出 NullPointerException。null 被用作指示 poll 操作失敗的警戒值。

BlockingQueue: 可以是限定容量的。它在任意給定時間都可以有一個 remainingCapacity,超出此容量,便無法無阻塞地 put 附加元素。沒有任何內部容量約束的 BlockingQueue 總是報告Integer.MAX_VALUE 的剩餘容量。

BlockingQueue :實現主要用於生產者-使用者隊列,但它另外還支持 Collection 接口。因此,舉例來說,使用 remove(x) 從隊列中移除任意一個元素是有可能的。然而,這種操作通常 會有效執行,只能有計劃地偶爾使用,比如在取消排隊信息時。

BlockingQueue :實現是線程安全的。所有排隊方法都可以使用內部鎖或其他形式的併發控制來自動達到它們的目的。然而,大量的 Collection 操作(addAll、containsAll、retainAll 和removeAll)沒有 必要自動執行,除非在實現中特別說明。因此,舉例來說,在只添加了 c 中的一些元素後,addAll(c) 有可能失敗(拋出一個異常)。

2 BlockingQueue理解

一個線程往裏邊放,另外一個線程從裏邊取的一個 BlockingQueue。

 一個線程將會持續生產新對象並將其插入到隊列之中,直到隊列達到它所能容納的臨界點。也就是說,它是有限的。如果該阻塞隊列到達了其臨界點,負責生產的線程將會在往裏邊插入新對象時發生阻塞。它會一直處於阻塞之中,直到負責消費的線程從隊列中拿走一個對象。

 負責消費的線程將會一直從該阻塞隊列中拿出對象。如果消費線程嘗試去從一個空的隊列中提取對象的話,這個消費線程將會處於阻塞之中,直到一個生產線程把一個對象丟進隊列。

3 自定義實現BlockingQueue

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 自定義實現有界阻塞隊列
 * 數組實現
 * Created by HH on 2019/7/17.
 */
public class MyArrayBlockingQueue<T> {
    /**
     * 隊列實現
     */
    private Object[] items;
    /**
     * 元素個數
     */
    private int count;

    /**
     * 準備插入位置
     */
    private int putIndex = 0;
    /**
     * 準備移除位置
     */
    private int removeIndex = 0;

    ReentrantLock lock = new ReentrantLock(true);
    /**
     * 隊列滿情況
     */
    Condition notFull = lock.newCondition();
    /**
     * 隊列爲空情況
     */
    Condition notEmpty = lock.newCondition();

    public MyArrayBlockingQueue(int size) {
        this.items = new Object[size];
    }

    /**
     * 進隊 插入最後一個元素位置
     *
     * @param t
     * @return
     * @throws InterruptedException
     */
    public void enqueue(T t) throws InterruptedException {
        //檢查是否爲空
        checkNull(t);
        //獲取鎖
        lock.lock();
        try {
            //已經滿了 則發生阻塞 無法繼續插入
            while (items.length == count) {
                System.out.println(t + "進隊阻塞,當前數據量" + count);
                notFull.await();
            }
            items[putIndex] = t;
            System.out.println("入隊:" + t);
            if (++putIndex == items.length) {
                putIndex = 0;
            }
            count++;
            notEmpty.signal();
        } finally {
            lock.unlock();
        }
    }

    /**
     * 出隊 最後一個元素
     *
     * @return
     */
    public Object dequeue() throws InterruptedException {
        lock.lock();
        Object o;
        try {
            while (count == 0) {
                System.out.println("出隊阻塞,當前數據量" + count);
                notEmpty.await();
            }
            o = this.items[removeIndex];
            this.items[removeIndex] = null;
            System.out.println("出隊:" + o);
            if (++removeIndex == items.length) {
                removeIndex = 0;
            }
            count--;
            notFull.signal();
        } finally {
            lock.unlock();
        }
        return o;
    }

    private void checkNull(T t) {
        if (t == null) {
            throw new NullPointerException();

        }
    }


    public static void main(String[] args) {
        MyArrayBlockingQueue<Object> objectMyArrayBlockingQueue = new MyArrayBlockingQueue<>(2);

        ExecutorService executorService = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 10; i++) {
            int data = i;
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        objectMyArrayBlockingQueue.enqueue(data);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }

        for (int i = 0; i < 10; i++) {

            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        objectMyArrayBlockingQueue.dequeue();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }
}

輸出效果如下:

 

這裏採用公平鎖,看控制檯輸出就可以看出

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章