缓冲区
public class Storage {
// 仓库最大存储量
private final int MAX_SIZE = 100;
// 仓库存储的载体
private LinkedList<Object> list = new LinkedList<Object>();
// 锁
private final Lock lock = new ReentrantLock();
// 仓库满的条件变量
private final Condition full = lock.newCondition();
// 仓库空的条件变量
private final Condition empty = lock.newCondition();
// 生产产品
public void produce() {
// 加锁
lock.lock();
// 满了
while (list.size() == MAX_SIZE) {
try {
full.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 不满
list.add(new Object());
// 唤醒empty阻塞队列中的线程
empty.signalAll();
// 释放锁
lock.unlock();
}
// 消费产品
public void consume() {
// 加锁
lock.lock();
// 空了
while (list.size() == 0) {
try {
empty.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 不空
list.remove();
// 唤醒full阻塞队列中的线程
full.signalAll();
// 释放锁
lock.unlock();
}
}
生产线程
public class Producer extends Thread {
private Storage storage;
public Producer(Storage storage){
this.storage = storage;
}
@Override
public void run(){
storage.produce();
}
}
消费线程
public class Consumer extends Thread {
private Storage storage;
public Consumer(Storage storage) {
this.storage = storage;
}
@Override
public void run() {
storage.consume();
}
}
关键点注释
模型由3部分构成:缓冲区、生产线程、消费线程。其中最关键的是缓冲区的编写。
由于频繁做add/remove操作,所以应该使用链式存储的LinkedList、LinkedHashMap等结构。
分别为“满了”和“空了”创建阻塞队列。当“满了”时,把调用(生产)线程加入“满了”阻塞队列;当“空了”时,把调用(消费)线程加入“空了”阻塞队列。当“不满”时,唤醒“空了”阻塞队列中的(消费)线程;当“不空”时,唤醒“满了”阻塞队列中的(生产)线程。
生产方法和消费方法结构差不多,记住1个也就记住了另1个。
- 临界区为整个方法;
- while(条件变量),条件变量是缓冲区满了或空了;
- while中await()交出CPU资源;
- while后执行add/remove操作;
- signalAll()唤醒相反的等待线程。