模板的核心:消费 / 生产方法
上锁
try{
while(...){
等待
}
进行消费 / 生产
通知
}catch (InterruptedException e) {
e.printStackTrace();
} finally {
需要手动解锁,则释放锁
}
关键点:try{}
扩住整个逻辑,这是不会影响性能的。具体请百度了解。
这样后续的finally,就可以在ReetrankLock等实现中,手动地释放锁,不需要则为空即可。不用担心忘记释放锁。
首先提醒一下,网上很多实现的解锁不是在 finally块中的,都是错的,无法保证释放锁。
然后,还有很多的实现是: 一个大try 套小try
try{
try{
while(){等待}
}catch(){}
进行消费
通知
}finally{
解锁
}
这种实现上自然没有问题,只是代码就会显得很冗余( = =,主要是写了一个try 之后就会放松警惕),所以笔者认为一个try搞定是最好的。
本文正文已完,附上本人实现代码。需要的可以参考一下。
前置:
生产消费者的实现,大致可以分成两种
-
抽象出仓库类,仓库类内部有queue,阻塞该queue。
生产者消费者,通过传入同一个仓库类,实现资源共享。在run方法中调用仓库类的方法即可
-
没有仓库类,生产消费者直接传入同一个队列。需要在 run 中 实现对应的生产、消费代码
本文采用第一种,抽象出仓库类。
而实现仓库类,常见的就是synchronized、ReentrantLock、直接用阻塞队列 三种。
本文只附上前两种实现,因为和模板比较贴合。
ps : 可以让两种实现同一个接口,测试起来会很方法,直接更改上转型对象即可
// 抽象个接口,方便测试不同的,实际没必要
public interface Storage {
void consume();
void produce();
}
测试的时候,直接更改实现类就可以了,很方便
// Storage storage = new StorageSync(10);
Storage storage = new StorageLock(10);
synchronized实现:
import java.util.LinkedList;
// 抽象个接口,方便测试不同的,实际没必要
public class StorageSync implements Storage {
//资源池中允许存放的资源数目
private int capacity;
private LinkedList<Integer> queue;
// 资源id,测试用
int i = 1;
public StorageSync(int capacity) {
this.capacity = capacity;
this.queue = new LinkedList<>();
}
public void consume() {
// 阻塞queue
synchronized (queue) {
// 其实只括await的部分就可以,不过为了整合Lock的实现。
// 但不影响性能
try {
// 自旋等待, 一定要用while,防止虚假唤醒 notifyAll
while (queue.size() == 0) {
System.out.println("【消费者" + Thread.currentThread().getName()
+ "】仓库为空");
queue.wait();
}
int i = queue.removeLast();
System.out.println("【消费者" + Thread.currentThread().getName()
+ "】消费一个产品" + i + ",现库存" + queue.size());
queue.notifyAll();//通知生产者生产资源
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void produce() {
synchronized (queue) {
try {
while (queue.size() == capacity) {
System.out.println("【生产者" + Thread.currentThread().getName()
+ "】仓库已满");
//生产者进入等待状态,并释放锁
queue.wait();
}
queue.addFirst(i);
System.out.println("【生产者" + Thread.currentThread().getName()
+ "】生产一个产品:" + i++ + ",现库存" + queue.size());
queue.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public int getNum() {
return queue.size();
}
}
Lock实现:
// 抽象个接口,方便测试不同的,实际没必要
public class StorageLock implements Storage {
private int capacity;
private LinkedList<Integer> queue;
// 资源id,测试用
int i = 1;
// final ,防止改变
private final ReentrantLock lock = new ReentrantLock();
// 消费者等待的条件 ,资源为0时等待
private final Condition consumerEmpty = lock.newCondition();
// 同,资源满了
private final Condition producerFull = lock.newCondition();
public StorageLock(int capacity) {
this.capacity = capacity;
this.queue = new LinkedList<>();
}
public void consume() {
lock.lock();
try {
while (queue.size() == 0) {
System.out.println("【消费者" + Thread.currentThread().getName()
+ "】仓库为空");
consumerEmpty.await();
}
int i = queue.removeLast();
System.out.println("【消费者" + Thread.currentThread().getName()
+ "】消费一个产品" + i + ",现库存" + queue.size());
producerFull.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void produce() {
lock.lock();
try {
while (queue.size() == capacity) {
System.out.println("【生产者" + Thread.currentThread().getName()
+ "】仓库已满");
producerFull.await();
}
queue.addFirst(i);
System.out.println("【生产者" + Thread.currentThread().getName()
+ "】生产一个产品:" + i++ + ",现库存" + queue.size());
consumerEmpty.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public int getNum() {
return queue.size();
}
}
生产、消费者、及测试类
package back.interview.ConsumerProducer;
import back.interview.ConsumerProducer.Storage.Storage;
import back.interview.ConsumerProducer.Storage.StorageLock;
class Producer implements Runnable {
private Storage storage;
// 传入storage
public Producer(Storage storage) {
this.storage = storage;
}
public void run() {
// storage.produce();
while (true) {
try {
Thread.sleep(1000);
storage.produce();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable {
private Storage storage;
public Consumer(Storage storage) {
this.storage = storage;
}
public void run() {
// storage.consume();
while (true) {
try {
Thread.sleep(3000);
storage.consume();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class test {
public static void main(String[] args) {
// Storage storage = new StorageSync(10);
Storage storage = new StorageLock(10);
// 关键,传入同一个Storage ,完成资源共享
Thread p1 = new Thread(new Producer(storage));
Thread p2 = new Thread(new Producer(storage));
Thread p3 = new Thread(new Producer(storage));
Thread c1 = new Thread(new Consumer(storage));
Thread c2 = new Thread(new Consumer(storage));
Thread c3 = new Thread(new Consumer(storage));
p1.start();
p2.start();
p3.start();
c1.start();
c2.start();
c3.start();
}
}
本文完,有误欢迎指出。