Queue主要方法的区别:
抛出异常 | 返回特殊值 | |
插入 | add(e)插入成功则返回true,没有可用空间则IllegalStateException | offer(e) |
移除 | remove(e)获取并移除,不存在则抛异常 | poll(e) |
检查 | element()获取元素,但并不移除,队列为空则抛出异常 | peek() |
Queue既可以是FIFO,也可以是按照一定优先级顺序排列,BlockingQueue区别在于对于空队列获取等待,满队列加入等待,适用于生产者消费者模型:
/** * Created by itworker365 on 6/2/2017. */ public class ThreadWNTest { public static void main (String[] args) throws InterruptedException { BlockingQueue blockingQueue = new ArrayBlockingQueue(10); Thread t1 = new Thread(new Runnable() { @Override public void run() { try { int i = 0; while (i < 100) { System.out.println("put :" + i++); blockingQueue.put(i++); } } catch (InterruptedException e) { e.printStackTrace(); } } }); t1.start(); Thread t2 = new Thread(new Runnable() { @Override public void run() { try { while (true) { System.out.println("take: " + blockingQueue.take()); } } catch (InterruptedException e) { e.printStackTrace(); } } }); t2.start(); System.out.println("start"); } }
ArrayBlockingQueue: 主要方法学习
包含一个object数组存放元素,takeIndex和putIndex分别包含放入和取出元素的位置,count表示当前元素个数,全局锁lock分别创建notFull和notEmpty(await/singnal)完成当元素满时添加等待,元素空时取元素等待。
class BasicBlockingQueue<E> { final Object[] items; int takeIndex; int putIndex; int count; final ReentrantLock lock; private final Condition notEmpty; private final Condition notFull; public BasicBlockingQueue (int capacity, boolean fair){ this.items = new Object[capacity]; lock = new ReentrantLock(fair); notEmpty = lock.newCondition(); notFull = lock.newCondition(); } //添加元素,如果添加元素为null则抛出异常,如果非null则获取全局锁 // 看添加元素后是否满足队列总长度限制,超出返回false,未超出则将元素添加到对应的items[putIndex]位置,并唤醒notEmpty.signal() private boolean offer(E e) { if (e == null) throw new NullPointerException(); final ReentrantLock lock = this.lock; lock.lock(); try { if (count == items.length) return false; else { enqueue(e); return true; } } finally { lock.unlock(); } } //带超时设定的这种 public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException { if (e == null) throw new NullPointerException(); long nanos = unit.toNanos(timeout); final ReentrantLock lock = this.lock; lock.lockInterruptibly(); try { while (count == items.length) { if (nanos <= 0) return false; nanos = notFull.awaitNanos(nanos); } enqueue(e); return true; } finally { lock.unlock(); } } //添加元素时,offer如果满了返回false,而add不能添加时则抛出异常 public boolean add(E e) { if (offer(e)) return true; else throw new IllegalStateException("Queue full"); } private void enqueue(E x) { final Object[] items = this.items; items[putIndex] = x; if (++putIndex == items.length) putIndex = 0; count++; notEmpty.signal(); } //取出元素,带超时的,获取全局锁,当元素为0,等待超时时间,一直没有就返回null,有的话就取出队列元素 public E poll(long timeout, TimeUnit unit) throws InterruptedException { long nanos = unit.toNanos(timeout); final ReentrantLock lock = this.lock; lock.lockInterruptibly(); try { while (count == 0) { if (nanos <= 0) return null; nanos = notEmpty.awaitNanos(nanos); } return dequeue(); } finally { lock.unlock(); } } private E dequeue() { final Object[] items = this.items; E x = (E) items[takeIndex]; items[takeIndex] = null; //不断循环使用 if (++takeIndex == items.length) takeIndex = 0; count--; notFull.signal(); return x; } }
LinkedBlockingQueue: 主要方法学习
元素存放在单向列表中,记录首尾节点,统计元素数目用atomicInteger,takelock和putlock分离,添加只需要修改last,取出只需要修改head
class BasicLinkedBlockingQueue<E> { private final int capacity = Integer.MAX_VALUE; //统计元素数目用AtomicInteger private final AtomicInteger count = new AtomicInteger(0); private transient Node<E> head; private transient Node<E> last; //分别创建takeLock和putLock private final ReentrantLock takeLock = new ReentrantLock(); private final Condition notEmpty = takeLock.newCondition(); private final ReentrantLock putLock = new ReentrantLock(); private final Condition notFull = putLock.newCondition(); //加入元素,包含超时,先获取putlock,跟array基本一样,元素数目用count.getAndIncrement()统计,然后释放锁,发放signalNotEmpty通知 public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException { if (e == null) throw new NullPointerException(); long nanos = unit.toNanos(timeout); int c = -1; final ReentrantLock putLock = this.putLock; final AtomicInteger count = this.count; putLock.lockInterruptibly(); try { while (count.get() == capacity) { if (nanos <= 0) return false; nanos = notFull.awaitNanos(nanos); } enqueue(new Node<E>(e)); c = count.getAndIncrement(); if (c + 1 < capacity) notFull.signal(); } finally { putLock.unlock(); } if (c == 0) signalNotEmpty(); return true; } //取得元素,带超时,先拿到takelock,和别的也一样 public E poll(long timeout, TimeUnit unit) throws InterruptedException { E x = null; int c = -1; long nanos = unit.toNanos(timeout); final AtomicInteger count = this.count; final ReentrantLock takeLock = this.takeLock; takeLock.lockInterruptibly(); try { while (count.get() == 0) { if (nanos <= 0) return null; nanos = notEmpty.awaitNanos(nanos); } x = dequeue(); c = count.getAndDecrement(); if (c > 1) notEmpty.signal(); } finally { takeLock.unlock(); } if (c == capacity) signalNotFull(); return x; } //添加只需要修改last private void enqueue(Node<E> node) { last = last.next = node; } //取出只需要修改head private E dequeue() { Node<E> h = head; Node<E> first = h.next; h.next = h; // help GC head = first; E x = first.item; first.item = null; return x; } private void signalNotEmpty() { final ReentrantLock takeLock = this.takeLock; takeLock.lock(); try { notEmpty.signal(); } finally { takeLock.unlock(); } } private void signalNotFull() { final ReentrantLock putLock = this.putLock; putLock.lock(); try { notFull.signal(); } finally { putLock.unlock(); } } } class Node<E> { E item; Node<E> next; Node(E x) { item = x; } }