生产者消费者问题有多种,本文阐述的是多个生产者生产商品,多个消费者消费商品,缓冲区中有多个商品,这种情况下应该怎么处理线程安全问题
首先,具体用一张图描述一下这种情形,达到的效果是,多个生产者一边生产,多个生产者一边消费。
需要注意两个临界情况
1.缓冲区满的时候,生产者不能继续生产
2.缓冲区空的时候,消费者不能继续消费
测试效果展示:
直接用代码解释实现过程会更加具体,所以看下代码实现(必要的地方都加上了注释)
- package ticket;
- import java.util.concurrent.locks.Condition;
- import java.util.concurrent.locks.Lock;
- import java.util.concurrent.locks.ReentrantLock;
- //Resous类描述的是资源
- class Resous{
- //定义一个上帝类型的数组,该数组可以放多种类型的元素
- final Object[] array=new Object[100];
- //锁对象
- private final Lock lock=new ReentrantLock();
- //两个监视器,notFull监视缓冲满没满,如果满了,则调用await()方法,使当前生产者线程等待,notEmpty同理
- private Condition notFull=lock.newCondition();
- private Condition notEmpty=lock.newCondition();
- //putx为生产者生产时使用的下标,takex消费者使用的下标,count为计数器,代表当前的资源数量
- int putx,takex,count;
- public void set(Object e) throws InterruptedException {
- lock.lock();
- try {
- //当缓冲区满的时候,生产者停止生产,进入等待状态
- while(count==array.length) {
- notFull.await();
- }
- //缓冲区加入一个商品
- array[putx]=e;
- //当生产者的下标等于缓冲区的容量时,将下标置为0,重新开始生产
- if(++putx==array.length)
- {
- putx=0;
- }
- ++count;//生产完一个商品之后,计数器加一
- System.out.println(Thread.currentThread().getName()+"生产者:当前容器中有"+count+"个商品");
- // 唤醒一个消费者消费
- notEmpty.signal();
- }finally {
- //不管何种情况,最后一定要保证释放锁,避免某个线程一直持有锁资源,而使其他生产者线程处于忙等状态
- //消费者线程同理
- lock.unlock();
- }
- }
- public void get() throws InterruptedException {
- lock.lock();
- try {
- //当缓冲区空的时候,消费者进入等待状态
- while(count==0) {
- notEmpty.await();
- }
- //消费者从缓冲区中取出一个商品
- Object e=array[takex];
- //如果消费者下标值等于缓冲区长度,则将其置为0,从头开始消费
- if(++takex==array.length) {
- takex=0;
- }
- //消费完一个商品之后,将计数器减一
- --count;
- System.out.println(Thread.currentThread().getName()+"消费者:当前容器中有"+count+"个商品");
- //唤醒一个生产者
- notFull.signal();
- }finally {
- lock.unlock();
- }
- }
- }
- class Pro implements Runnable{
- Resous r;
- public Pro(Resous r) {
- this.r=r;
- }
- @Override
- public void run() {
- try {
- while(true) {
- r.set("面包");
- }
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- class Cons implements Runnable{
- Resous r;
- public Cons(Resous r) {
- this.r=r;
- }
- @Override
- public void run() {
- try {
- while(true) {
- r.get();
- }
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- //BoundBuffer 测试类
- public class BoundBuffer {
- public static void main(String[] args) {
- Resous r=new Resous();
- Pro p=new Pro(r);
- Cons c=new Cons(r);
- Thread t1=new Thread(p);
- Thread t2=new Thread(p);
- Thread t3=new Thread(c);
- Thread t4=new Thread(c);
- t1.start();
- t2.start();
- t3.start();
- t4.start();
- }
- }