1. BlockingQueue接口的常用实现类如下:
BlockingQueue定义的常用方法如下:
抛出异常 特殊值 阻塞 超时
插入 add(e) offer(e) put(e) offer(e, time, unit)
移除 remove() poll() take() poll(time, unit)
检查 element() peek() 不可用 不可用
解释:
add: 如果当前队列已满,执行add操作将抛出异常
offer: 如果当前队列已满,执行offer操作将返回false(JDK6)
put: 如果当前队列已满,则无限期阻塞下去直到队列可插入
take: 如果当前队列为空,则无限期阻塞下去直到队列非空
2. LinkedBlockingQueue
实例化代码:
public LinkedBlockingQueue(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
last = head = new Node<E>(null);//创建一个Node,令head和last都指向这位对象
}
从实例化源码可以看出LinkedBlockingQueue是用链表结构实现的,实例化时并不分配所有空间
add():
public boolean add(E e) {
if (offer(e))//add操作实际是调用了offer
return true;
else
throw new IllegalStateException("Queue full");//如果队列已满则抛出异常
}
offer():
public boolean offer(E e) {
if (e == null) throw new NullPointerException();
final AtomicInteger count = this.count;
if (count.get() == capacity)//队列已满,链表长度等于初始化时的capacity
return false;
int c = -1;
final ReentrantLock putLock = this.putLock;
putLock.lock();//对enqueue操作加锁
try {
if (count.get() < capacity) {
enqueue(e);
c = count.getAndIncrement();
if (c + 1 < capacity)
notFull.signal();//唤醒读线程
}
} finally {
putLock.unlock();//ReentrantLock一定要在finally中释放锁
}
if (c == 0)
signalNotEmpty();
return c >= 0;
}
可见队列满的情况下仅仅返回false
put()
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
// Note: convention in all put/take/etc is to preset local var
// holding count negative to indicate failure unless set.
int c = -1;
final ReentrantLock putLock = this.putLock;
final AtomicInteger count = this.count;
putLock.lockInterruptibly();
try {
/*
* Note that count is used in wait guard even though it is
* not protected by lock. This works because count can
* only decrease at this point (all other puts are shut
* out by lock), and we (or some other waiting put) are
* signalled if it ever changes from
* capacity. Similarly for all other uses of count in
* other wait guards.
*/
while (count.get() == capacity) {
notFull.await();//如果队列已满,则阻塞写线程
}
enqueue(e);
c = count.getAndIncrement();
if (c + 1 < capacity)
notFull.signal();//唤醒写线程
} finally {
putLock.unlock();//释放锁
}
if (c == 0)
signalNotEmpty();
}
//插到队尾
private void enqueue(E x) {
// assert putLock.isHeldByCurrentThread();
last = last.next = new Node<E>(x);
}
take():
public E take() throws InterruptedException {
E x;
int c = -1;
final AtomicInteger count = this.count;
final ReentrantLock takeLock = this.takeLock;
takeLock.lockInterruptibly();
try {
while (count.get() == 0) {
notEmpty.await();
}
x = dequeue();
c = count.getAndDecrement();
if (c > 1)
notEmpty.signal();
} finally {
takeLock.unlock();
}
if (c == capacity)
signalNotFull();
return x;
}
//将队列头的元素返回
private E dequeue() {
// assert takeLock.isHeldByCurrentThread();
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;
}
poll():
public E poll() {
final AtomicInteger count = this.count;
if (count.get() == 0)
return null;//如果队列空则返回null
E x = null;
int c = -1;
final ReentrantLock takeLock = this.takeLock;
takeLock.lock();
try {
if (count.get() > 0) {
x = dequeue();//队列非空,获取头元素
c = count.getAndDecrement();
if (c > 1)
notEmpty.signal();//唤醒写线程
}
} finally {
takeLock.unlock();
}
if (c == capacity)
signalNotFull();
return x;
}
3. ArrayBlockingQueue
实例化代码:
public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException();
//实例化的时候就分配一个数组空间 注意与LinkedBlockingQueue的区别
this.items = (E[]) new Object[capacity];
lock = new ReentrantLock(fair);
notEmpty = lock.newCondition();
notFull = lock.newCondition();
}
add():
//同LinkedBlockingQueue的add
public boolean add(E e) {
return super.add(e);
}
offer():
public boolean offer(E e) {
if (e == null) throw new NullPointerException();
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count == items.length)
return false;//数组已满,返回false
else {
insert(e);//插入数组
return true;
}
} finally {
lock.unlock();
}
}
private void insert(E x) {
items[putIndex] = x;
putIndex = inc(putIndex);//索引加1
++count;
notEmpty.signal();//唤醒写线程
}
4. SynchronousQueue
同步Queue,属于线程安全的BlockingQueue的一种,此队列设计的理念类似于"单工模式",对于每个put/offer操作,必须等待一个take/poll操作,类似于我们的现实生活中的"火把传递":一个火把传递地他人,需要2个人"触手可及"才行. 因为这种策略,最终导致队列中并没有一个真正的元素;这是一种pipleline思路的基于queue的"操作传递".
void put(E o):向队列提交一个元素,阻塞直到其他线程take或者poll此元素.
boolean offer(E o):向队列中提交一个元素,如果此时有其他线程正在被take阻塞(即其他线程已准备接收)或者"碰巧"有poll操作,那么将返回true,否则返回false.
E take():获取并删除一个元素,阻塞直到有其他线程offer/put.
boolean poll():获取并删除一个元素,如果此时有其他线程正在被put阻塞(即其他线程提交元素正等待被接收)或者"碰巧"有offer操作,那么将返回true,否则返回false.
E peek():总会返回null,硬编码.(转)