对于一个共享的缓冲区里,多个消费者进程与生产者进程并发访问,消费者进程每次消耗一个物品,生产者进程每次生产一个物品,需要注意的是:
1、当缓冲区满了的时候生产者将不能再次生产;
2、当缓冲区为空时消费者进程亦不能再次消费;
3、缓冲区属于临界资源,各进程需要互斥访问。
实现代码如下:
import java.util.LinkedList;
import java.util.List;
class Conternier<T>{
private List<T> list = new LinkedList<T>();
private int max = 10;
// private int count = 0;
public synchronized void put(T e) {
while(max == list.size()) {//满了不能再放了
try {
this.wait();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
list.add(e);
this.notifyAll();
System.out.println(Thread.currentThread().getName() +"生产了"+ list.size());
}
public synchronized T get() {
while(list.size() == 0) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notifyAll();
System.out.println(Thread.currentThread().getName() +"消费了"+ list.size());
return list.remove(0);
}
}
public class TestConsumerProducer {
public static void main(String[] args) {
Conternier<String> conternier = new Conternier<>();
for(int i = 0;i < 2;i++) {//两个生产者
new Thread(()->{
for(int j = 0;j < 25;j++) {
conternier.put("goods");
}
},"producer"+i).start();
}
for(int i = 0;i < 2;i++) {
new Thread(()->{
for(int j = 0;j < 25;j++) {
conternier.get();
}
},"consumer"+i).start();
}
}
}
两点注明:
注1:producer中为何是用while(max == list.size())而不使用if(max == list.size())?
假设使用的是if,在缓冲区装满的情况下进来了两个生产者进程A,B,于是这两个进程都进入等待态。当消费者进程消费了一个后,将这两个进程都唤醒了。(注意此时唤醒之后是会直接到之前wait()的后一行)A进程先生产了一个然后满了将自己wait(),轮到B进程,此时虽然缓冲区已经满了,但是B进程已经跳过了check的部分,因此其仍然会再次生产。
使用while就不会存在这个问题,由于唤醒之后依然在while()里面,想要跳出wile仍然需要一次check。因此可以避免上述状况。
注2:进程一次执行完之后为啥使用的是notifyAll()而不能是notify()呢?
假如使用的是notify(),当一个生产者进程生产完刚把缓冲区填满,其将会执行notify()如果恰好唤醒的又是一个生产者,如此便会使所有的线程全进入wait。