生活
有很多的不快乐,其实是源自不满足,而不满足,很多时候是源自于心不定,而心不定则是因为不清楚究竟自己要什么,不清楚要什么的结果就是什么都想要,结果什么都没得到。
生产者消费者模式
生产者和消费者问题是线程模型中一个经典问题:
生产者和消费者在同一个时间段内共用一块内存区域,由生产者在这块内存区域创建消费者需要的数据,由消费者取走数据并消费。
对于生产者消费者模型的应用实例,JDK1.5提供了阻塞队列。
下面来看下ArrayBlockingQueue,这是一个有界的,数组结构的阻塞队列。
ArrayBlockingQueue 成员组成
先来看下ArrayBlockingQueue的成员组成:
//元素容器
final Object[] items;
//出队索引
int takeIndex;
//入队索引
int putIndex;
//队列中元素个数
int count;
//锁
final ReentrantLock lock;
//出队条件
private final Condition notEmpty;
//入队条件
private final Condition notFull;
组成明了,出队和入队各有一个条件,互不干扰。
ArrayBlockingQueue 之创建
//创建指定长度的非公平 有界数组阻塞队列
public ArrayBlockingQueue(int capacity) {
this(capacity, false);
}
//可以指定fair为true创建公平的队列
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;
}
} catch (ArrayIndexOutOfBoundsException ex) {
throw new IllegalArgumentException();
}
count = i;
putIndex = (i == capacity) ? 0 : i;
} finally {
lock.unlock();
}
}
ArrayBlockingQueue 之生产
不阻塞生产:
//调用offer,如果满了就报错
public boolean add(E e) {
return super.add(e);
}
//
public boolean offer(E e) {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
//满了就返回false;
if (count == items.length)
return false;
else {
insert(e);
return true;
}
} finally {
lock.unlock();
}
}
阻塞生产:
//阻塞一定时间,不能入队就返回false,可以中断
public boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException {
checkNotNull(e);
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);
}
insert(e);
return true;
} finally {
lock.unlock();
}
}
// 一直阻塞直到入队或者被中断
public void put(E e) throws InterruptedException {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
//当队列满时等待
while (count == items.length)
notFull.await();
insert(e);
} finally {
lock.unlock();
}
}
核心入队方法:
private void insert(E x) {
items[putIndex] = x;
putIndex = inc(putIndex);
++count;
//入队成功后唤醒等到在NotEmpty上的线程
notEmpty.signal();
}
ArrayBlockingQueue 之消费
不阻塞消费:
// 没有元素返回null,有就返回并移除队列中该元素
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return (count == 0) ? null : extract();
} finally {
lock.unlock();
}
}
//不阻塞返回数据 不移除队列
public E peek() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return (count == 0) ? null : itemAt(takeIndex);
} finally {
lock.unlock();
}
}
阻塞消费:
//一直阻塞值到出队 或者被中断
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0)
notEmpty.await();
return extract();
} finally {
lock.unlock();
}
}
//阻塞消费,超时后返回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 extract();
} finally {
lock.unlock();
}
}
出队核心方法:
private E extract() {
final Object[] items = this.items;
E x = this.<E>cast(items[takeIndex]);
items[takeIndex] = null;
//移除元素后并没有整体往前挪,只是索引+1
takeIndex = inc(takeIndex);
--count;
//出队成功后唤醒等待在NotFull上的线程
notFull.signal();
return x;
}
实例
public class ABQTest {
public static class Bread{
String name;
String price;
public Bread(String name, String price) {
this.name = name;
this.price = price;
}
@Override
public String toString() {
return String.format("[面包:%s,价格:%s]",name,price);
}
}
public static class Producer implements Runnable{
private ArrayBlockingQueue<Bread> queue;
private Bread bread;
private String name;
private CountDownLatch latch;
@Override
public void run() {
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
Thread.sleep(Long.valueOf(new Random().nextInt(1000)));
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
queue.put(bread);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(String.format("name:%s,生产:%s",name,bread.toString()));
}
public Producer(ArrayBlockingQueue<Bread> queue, Bread bread, String name, CountDownLatch latch) {
this.queue = queue;
this.bread = bread;
this.name = name;
this.latch = latch;
}
}
public static class Consumer implements Runnable{
private ArrayBlockingQueue<Bread> queue;
private String name;
private CountDownLatch latch;
@Override
public void run() {
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
Thread.sleep(Long.valueOf(new Random().nextInt(1000)));
} catch (InterruptedException e) {
e.printStackTrace();
}
Bread bread = null;
try {
bread=queue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(String.format("name:%s,买了:%s",name,bread.toString()));
}
public Consumer(ArrayBlockingQueue<Bread> queue, String name, CountDownLatch latch) {
this.queue = queue;
this.name = name;
this.latch = latch;
}
}
public static void main(String[] args) {
CountDownLatch latch = new CountDownLatch(1);
ArrayBlockingQueue<Bread> queue = new ArrayBlockingQueue<Bread>(4);
new Thread(new Producer(queue,new Bread("肉松","10"),"赵",latch)).start();
new Thread(new Producer(queue,new Bread("蛋黄","7"),"钱",latch)).start();
new Thread(new Producer(queue,new Bread("火腿","15"),"孙",latch)).start();
new Thread(new Producer(queue,new Bread("蔬菜","5"),"李",latch)).start();
new Thread(new Producer(queue,new Bread("香肠","8"),"周",latch)).start();
new Thread(new Consumer(queue,"A",latch)).start();
new Thread(new Consumer(queue,"B",latch)).start();
new Thread(new Consumer(queue,"C",latch)).start();
new Thread(new Consumer(queue,"D",latch)).start();
new Thread(new Consumer(queue,"E",latch)).start();
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
latch.countDown();
}
}
name:钱,生产:[面包:蛋黄,价格:7]
name:周,生产:[面包:香肠,价格:8]
name:A,买了:[面包:蛋黄,价格:7]
name:B,买了:[面包:香肠,价格:8]
name:赵,生产:[面包:肉松,价格:10]
name:E,买了:[面包:肉松,价格:10]
name:孙,生产:[面包:火腿,价格:15]
name:C,买了:[面包:火腿,价格:15]
name:D,买了:[面包:蔬菜,价格:5]
name:李,生产:[面包:蔬菜,价格:5]