数组阻塞队列 ArrayBlockingQueue

前言


ArrayBlockingQueue这个是数组阻塞队列,是BlockingQueue接口的一个实现类,它是一个容量有限的队列,一旦队列大小确认了就不能再改变了,使用方法,下面介绍。

使用


import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class Main1 {
    public static void main(String[] args) {
        // 准备好数组阻塞队列
        BlockingQueue<Integer> bq = new ArrayBlockingQueue<Integer>(1024);
        // 两个Runnable实现类
        Producer producer = new Producer(bq);
        Consumer consumer = new Consumer(bq);
        Thread t1 = new Thread(producer);
        Thread t2 = new Thread(consumer);

        // 线程开启
        t1.start();
        t2.start();


    }
}

class Producer implements Runnable {
    private BlockingQueue<Integer> blockingQueue = null;

    public Producer() {
    }

    public Producer(BlockingQueue<Integer> blockingQueue) {
        this.blockingQueue = blockingQueue;
    }

    @Override
    public void run() {
        // try catch主要是put(null),会抛出Exception
        try {
            // 为了实现一个生产慢,消费快,消费阻塞的效果
            Thread.sleep(1000);
            blockingQueue.put(1);
            Thread.sleep(1000);
            blockingQueue.put(4);
            Thread.sleep(1000);
            blockingQueue.put(555);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class Consumer implements Runnable {
    private BlockingQueue<Integer> blockingQueue = null;

    public Consumer() {
    }

    public Consumer(BlockingQueue<Integer> blockingQueue) {
        this.blockingQueue = blockingQueue;
    }

    @Override
    public void run() {
        try {
            System.out.println(blockingQueue.take());
            System.out.println(blockingQueue.take());
            System.out.println(blockingQueue.take());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

源码解析

其实这个ArrayBlockingQueue的源码并不难,底层就是一个数组在进行操作,我们通过上面的那个Demo代码,进行debug,然后来探究一下到底底层是如何操作的。

// 实例化就不多说了
    /**
     * Creates an {@code ArrayBlockingQueue} with the given (fixed)
     * capacity and default access policy.
     *
     * @param capacity the capacity of this queue 队列的容量
     * @throws IllegalArgumentException if {@code capacity < 1}
     */
    public ArrayBlockingQueue(int capacity) {
        this(capacity, false);
    }

    public ArrayBlockingQueue(int capacity, boolean fair) {
        // 判断传进来设置的队列容量是不是正整数
        if (capacity <= 0)
            // 不是肯定要抛出异常,你玩儿我?
            throw new IllegalArgumentException();
        //  final Object[] items; 这个items就是个Object类型的数组
        this.items = new Object[capacity];
        // 这个锁肯定是要用的,用的是ReentrantLock
        lock = new ReentrantLock(fair);
        // 两个监视器用于队列满和队列用阻塞之时使用。
        notEmpty = lock.newCondition();
        notFull =  lock.newCondition();
    }   

    // 当生产者调用put方法时

    public void put(E e) throws InterruptedException {
        // 查看放进队列的对象是不是null,是则抛出NPE
        checkNotNull(e);
        // 拿到前面初始化时候的那把锁
        final ReentrantLock lock = this.lock;
        // 加锁,其他线程没法用下面的方法了
        lock.lockInterruptibly();
        try {
            // 看看这个队列里面有多少个数,是不是比容量大了
            while (count == items.length)
                // 队列满了,就等待
                notFull.await();
            // 没满就入列
            enqueue(e);
        } finally {
            // 解锁操作不能忘
            lock.unlock();
        }
    }

    // 入列操作

    private void enqueue(E x) {
        // assert lock.getHoldCount() == 1;
        // assert items[putIndex] == null;
        final Object[] items = this.items;
        items[putIndex] = x;
        if (++putIndex == items.length)
            putIndex = 0;
        count++;
        // 告诉阻塞的队列空监视器,现在不空了。
        notEmpty.signal();
    }

    // take操作

    public E take() throws InterruptedException {
        // 拿锁
        final ReentrantLock lock = this.lock;
        // 加锁
        lock.lockInterruptibly();
        try {
            // 如果队列里面没东西
            while (count == 0)
                // 阻塞
                notEmpty.await();
            // 有东西,就返回一个对象
            return dequeue();
        } finally {
            // 释放锁
            lock.unlock();
        }
    }

    // 出列操作

    private E dequeue() {
        // assert lock.getHoldCount() == 1;
        // assert items[takeIndex] != null;
        // 拿到这个所谓的队列
        final Object[] items = this.items;
        @SuppressWarnings("unchecked")
        // 一个泛型操作
        E x = (E) items[takeIndex];
        // 取出的话,数组对应地方肯定是空了
        items[takeIndex] = null;
        if (++takeIndex == items.length)
            takeIndex = 0;
        // 计数也要有相应的变化
        count--;
        if (itrs != null)
            itrs.elementDequeued();
        // 告诉阻塞的满信号,队列不满了
        notFull.signal();
        return x;
    }

后记


所以,其实我们后面大部分业务场景用的就是用这个数组阻塞队列,不过,既然是学习的话,当然是其他实现类也是要看看了。

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