允许多生产消费者使用队列
JDK注释中的生产消费者代码,允许有多个生产者和多个消费者。
class Producer implements Runnable {
private final BlockingQueue queue;
Producer(BlockingQueue q) { queue = q; }
public void run() {
try {
while (true) { queue.put(produce()); }
} catch (InterruptedException ex) { ... handle ...}
}
Object produce() { ... }
}
class Consumer implements Runnable {
private final BlockingQueue queue;
Consumer(BlockingQueue q) { queue = q; }
public void run() {
try {
while (true) { consume(queue.take()); }
} catch (InterruptedException ex) { ... handle ...}
}
void consume(Object x) { ... }
}
class Setup {
void main() {
BlockingQueue q = new SomeQueueImplementation();
Producer p = new Producer(q);
Consumer c1 = new Consumer(q);
Consumer c2 = new Consumer(q);
new Thread(p).start();
new Thread(c1).start();
new Thread(c2).start();
}
}
阻塞队列几种放入元素和取出元素的区别
插入元素都不能为null,使用ReentrantLock保证线程安全。
插入元素
offer(E e)
往队列插入一个元素,如果容量足够,插入成功返回true,否则返回失败false。
add(E e)
往队列添加元素,如果容量足够,插入成功返回true,否则抛出异常。建议使用offer(E e)而不是用add(E e)。
put(E e)
往队列插入一个元素,无返回值。如果容量不够,阻塞等待。
offer(E e, long timeout, TimeUnit unit)
往队列插入一个元素,如果队列满了,等待指定时间,返回boolean。
取出元素,会移除头部元素
remove(Object o)
移除队列中的指定元素,如果有多个(equals返回true),移除一个,返回true。如果没有,返回false。
poll()
从队列移除一个元素,如果没有,返回null。
take()
从队列取出一个元素,如果队列为空,阻塞等待。
poll(time, unit)
从队列去除一个元素,如果队列为空,阻塞等待指定时间,如果仍然没有元素,返回null。
检查队列是否为空,不移除头部元素
element()
检索但不删除队列头部,如果队列为空,抛出异常。
peek()
检索但不删除队列头部,如果队列为空,返回null。
阻塞队列中,如果队列满/空,阻塞等待被唤醒的实现方式
定义
final ReentrantLock lock;
/** Condition for waiting takes */
private final Condition notEmpty;
/** Condition for waiting puts */
private final Condition notFull;
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 E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0)
// 阻塞等待put()中notEmpty.signal()
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;
if (++takeIndex == items.length)
takeIndex = 0;
count--;
if (itrs != null)
itrs.elementDequeued();
// 将线程从notFull.await()唤醒
notFull.signal();
return x;
}
放入元素
public void put(E e) throws InterruptedException {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == items.length)
// 等待take()方法的notFull.signal()
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;
if (++putIndex == items.length)
putIndex = 0;
count++;
// 唤醒put()里notEmpty.await()中的线程
notEmpty.signal();
}