这些阻塞队列都实现了BlockingQueue接口
阻塞队列的操作方法
在阻塞队列中,提供了四种处理方式
1. 插入操作
add(e) :添加元素到队列中,如果队列满了,继续插入
元素会报错,IllegalStateException。
offer(e) : 添加元素到队列,同时会返回元素是否插入
成功的状态,如果成功则返回 trueput(e) :当阻塞队列满了以后,生产者继续通过 put
添加元素,队列会一直阻塞生产者线程,知道队列可用
offer(e,time,unit) :当阻塞队列满了以后继续添加元素,
生产者线程会被阻塞指定时间,如果超时,则线程直接
退出
2. 移除操作
remove():当队列为空时,调用 remove 会返回 false,
如果元素移除成功,则返回 true
poll(): 当队列中存在元素,则从队列中取出一个元素,
如果队列为空,则直接返回 null
take():基于阻塞的方式获取队列中的元素,如果队列为
空,则 take 方法会一直阻塞,直到队列中有新的数据可
以消费
poll(time,unit):带超时机制的获取数据,如果队列为空,
则会等待指定的时间再去获取元素返回
例 import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.TimeUnit; /** * @author sun * @date 2019/8/30 */ public class ArrayBlockQueueTest { static ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue(10); static volatile boolean isRun=true; public static void main(String[] args) { new Thread(){ @Override public void run() { for(int i=0;i<100;i++) { try { blockingQueue.put(i); Thread.sleep(1); System.out.println("add number is :"+i); } catch (InterruptedException e) { e.printStackTrace(); } } isRun=false; } }.start(); new Thread(){ @Override public void run() { while ( isRun) { try { System.out.println(blockingQueue.poll(10, TimeUnit.MILLISECONDS));//取到空就会结束 } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("所有数据取完"); } }.start(); } }
我们不难发现大多数阻塞队列都是用到了ReentrantLock和Condition,
以ArrayBlockingQueue源码来简单分析一下,有3个构造函数
构造函数基于非公平锁 构造函数一 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(); }
构造函数三,最后一个变量表示可以在初化的时候就添加一部分值 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;//items数组大小 } } catch (ArrayIndexOutOfBoundsException ex) { throw new IllegalArgumentException(); } count = i; putIndex = (i == capacity) ? 0 : i;//putIndex放元素的位置 } finally { lock.unlock(); } }
put方法
public void put(E e) throws InterruptedException { 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;//putIndex当前元素放到数组位置 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;//takeIndex 取数组元数的下标 if (++takeIndex == items.length) takeIndex = 0; count--; if (itrs != null) itrs.elementDequeued();//更新迭代器中的元素 notFull.signal(); return x; }