ArrayBlockingQueue浅析

来源:互联网 发布:linux ssr 客户端 编辑:程序博客网 时间:2024/05/29 17:29

BlockingQueue是java的一个线程安全的阻塞队列的接口,

ArrayBlockingQueue 实现了 此接口,很简单,从名字上可以看出来,内部是 数组 实现的

ArrayBlockingQueue 源码中的部分变量:

    final Object[] items;  //存储所有元素的地方    int takeIndex;  //获取元素的时候就是取出  takeIndex位置的元素    int putIndex;  //添加元素根据 putIndex添加到指定位置    int count;  //队列中的元素个数    final ReentrantLock lock;    /**    ArrayBlockingQueue就是通过notEmpty和 notFull来实现阻塞功能的 */    private final Condition notEmpty;      private final Condition notFull;    transient Itrs itrs = null;    //暂时不知道用来干嘛的


offer方法,用于往队列里面添加元素,

public boolean offer(E e) {        checkNotNull(e);     //判断是否为null        final ReentrantLock lock = this.lock;        lock.lock();          try {            //如果队列已满,返回false            if (count == items.length)                return false;            else {                enqueue(e); //入 队                return true;            }        } finally {            lock.unlock();        }    }

enqueue方法:

 private void enqueue(E x) {        final Object[] items = this.items;        items[putIndex] = x;     //元素x放入 putIndex的位置        if (++putIndex == items.length)       //先putIndex加一,再判断putIndex到达末尾,再从0开始            putIndex = 0;        count++;        notEmpty.signal();  //通知 正在 notEmpty上等待的线程,     }

put方法,若元素已满会一直等待

public void put(E e) throws InterruptedException {        checkNotNull(e);        final ReentrantLock lock = this.lock;        lock.lockInterruptibly();          try {            while (count == items.length)                notFull.await();  //等待,直到dequeue方法获取元素后调用notFull.signal()            enqueue(e);        } finally {            lock.unlock();        }    }

take方法,从队列获取元素,若没有,则等待

public E take() throws InterruptedException {        final ReentrantLock lock = this.lock;        lock.lockInterruptibly();        try {            while (count == 0)                   notEmpty.await();  //没有元素就等待            return dequeue();  //出队        } finally {            lock.unlock();        }    }


dequeue方法

  private E dequeue() {        final Object[] items = this.items;        E x = (E) items[takeIndex];  //获取takIndex位置的元素        items[takeIndex] = null;  //将takeIndex的元素设置为null        if (++takeIndex == items.length)  //先takeIndex加一,在判断是否等于数组长度            takeIndex = 0;        count--;        if (itrs != null)            itrs.elementDequeued();        notFull.signal();  //唤醒正在等待 notFull的线程        return x;    }

ArrayBlockingQueue的方法不多,基本就2大类

一类是  获取元素,如 poll,, take,peek

一类是 添加元素,如 add ,offer,put


然后各自实现了不同的特性, 如  获取(取出)不到是 继续等待,还是返回false 还是抛出异常等

内部用 ReentrantLock 实现同步,

当添加元素时,通过 notFull阻塞,  直到 等待 dequeue方法调用,唤醒notFull的线程

同理, 当获取元素时, 通过 notEmpty阻塞,  等待  enqueue方法调用,唤醒notEmpty的线程

简单且实用