阻塞队列之ArrayBlockingQueue

ArrayBlockingQueue是一个有界阻塞队列,内部用数组存储元素,初始化的需要指定容量大小,底层用ReentrantLock来保证线程安全.

例子如下:

public class ArrayBlockingQueueDemo {

    public static void main(String[] args) throws Exception {
        //使用ArrayBlockingQueue初始化一个BlockingQueue,指定容量的上限为1024
        BlockingQueue queue = new ArrayBlockingQueue(1024);

        //生产者
        Producer producer = new Producer(queue);
        //消费者
        Consumer consumer = new Consumer(queue);

        //开启生产者线程
        new Thread(producer).start();
        //开启消费者线程
        new Thread(consumer).start();  

        Thread.sleep(4000);
    }
}
生产者如下:
public class Producer implements Runnable {

    protected BlockingQueue queue = null;

    public Producer(BlockingQueue queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        try {
            for (int i = 0; i < 3; i++) {
                queue.put(i);
                System.out.println("produce " + i);
                Thread.sleep(10000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
消费者如下:
public class Consumer implements Runnable{

    protected BlockingQueue queue = null;

    public Consumer(BlockingQueue queue) {
        this.queue = queue;
    }

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

运行结果如下:

1:从运行结果可以看出来,生产者放入一个值,就会消费一个.生产者和消费者效率速度匹配的情况下还是不错的.如果任何一方过快或者过慢,都会造成线程的阻塞.

2:从这个例子中,我们可以看到几个关键的方法.

方法探究:

1:构造方法:
  public ArrayBlockingQueue(int capacity) {
        this(capacity, false);
    }
  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();
    }

1.1:从构造方法我们可以看出,这个阻塞队列是支持公平和非公平两种模式.

1.2:如果我们传入的容量参数小于等于0会抛出异常.

1.3:内部存储元素的数据结构是一个数组.

1.4:内部运用的锁是ReentrantLcok,阻塞队列运用的是condition.

(ReentrantLcok前面有相关的文章可以参考,这里就不过多赘述了.)

2:构造方法
 public ArrayBlockingQueue(int capacity, boolean fair,
                              Collection<? extends E> c) {
        this(capacity, fair);

        final ReentrantLock lock = this.lock;
        lock.lock(); // Lock only for visibility, not mutual exclusion
        try {
            int i = 0;
            try {
                for (E e : c) {
                    checkNotNull(e);
                    items[i++] = e;
                }
            } catch (ArrayIndexOutOfBoundsException ex) {
                throw new IllegalArgumentException();
            }
            count = i;
            putIndex = (i == capacity) ? 0 : i;
        } finally {
            lock.unlock();
        }
    }

这个构造方法和上面的区别是这个可以传入一个数组.

2.1:通过获取锁操作,来保证多线程下的初始化唯一.

2.2:通过循环给items数组进行赋值.

2.3:checkNotNull方法:

 private static void checkNotNull(Object v) {
        if (v == null)
            throw new NullPointerException();
    }

如果传入的数组为空的话抛出空指针异常.

2.4:count:当前队列里的元素数量.

2.5:putIndex:放入元素的指针.(就是位置,如果i等于当前容量,就重置为0,是一个环形数组.).

3.put方法:
void put(E e) throws InterruptedException;

3.1:enqueue方法:

注意:这里的唤醒并不是真正的唤醒,只是把线程从条件队里转移到同步队列,然后释放锁的时候去真正唤醒.

4.take方法:
E take() throws InterruptedException;

4.1dequeue方法:

4.2:itrs是一个迭代器,我们可以通过迭代器遍历这个阻塞队列,一般情况下这个都是空.

4.3elementDequeued方法:

 void elementDequeued() {
            // assert lock.getHoldCount() == 1;
            if (count == 0)
                queueIsEmpty();
            else if (takeIndex == 0)
                takeIndexWrapped();
        }

4.4如果当前队列没有元素的话,进入queueIsEmpty方法:

4.5如果取指针为0的话,进入takeIndexWrapped方法:

 void takeIndexWrapped() {
            // assert lock.getHoldCount() == 1;
            cycles++;
            for (Node o = null, p = head; p != null;) {
                final Itr it = p.get();
                final Node next = p.next;
                if (it == null || it.takeIndexWrapped()) {
                    // unlink p
                    // assert it == null || it.isDetached();
                    p.clear();
                    p.next = null;
                    if (o == null)
                        head = next;
                    else
                        o.next = next;
                } else {
                    o = p;
                }
                p = next;
            }
            if (head == null)   // no more iterators to track
                itrs = null;
        }

这个方法大概就是要把已经出队的元素进行清除.(这个阻塞队列的迭代器没有太多深入了解,有懂的小伙伴,可以指点一二,让我少走点弯路.) 

没有伞的孩子,他,只能奔跑.

如果大家喜欢我的分享的话,可以关注我的微信公众号

念何架构之路

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值