生产者消费者问题(多生产者多消费者多缓冲区)——Java多线程

  • 题目要求:

提供三种场景供用户选择:
1、单生产者单消费者单缓冲区
2、多生产者多消费者单缓冲区
3、多生产者多消费者多缓冲区
用户可以自由选择三种场景,并输入可选择参数。

  • 场景解析

1、单生产者单消费者单缓冲区:为一对一的情况,所需要考虑的仅有生产者和消费者对缓冲区的互斥操作。
2、多生产者多消费者单缓冲区:不仅要考虑生产者消费者之间的互斥,为了避免多个生产者生产的产品放到缓冲区中的同一个位置、多个消费者消费同一个产品,还要考虑生产者之间、消费者之间的互斥关系。
3、多生产者多消费者多缓冲区:与前两种场景不同之处在于,由于是多缓冲区,因此,当生产者碰到已满的缓冲区时,此时不再等待,而是选择另外未满的缓冲区,此场景与第二种场景存在相同的互斥要求。

  • 解决思路

结合Java多线程和面向对象程序设计进行此次实验的代码开发,本解决方案采用多线程中较为简单的部分,适用于对多线程了解较少的人。

  • 基础知识

Java多线程相关:
1、关键字synachronized:用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块时,同时刻最多只有一个线程执行这段代码。
使用方法:
①方法说明时使用,一次只能由一个线程进入该方法,此时线程获得的是成员锁。如:public synchronized void synMethod(){//方法体}
②对某一代码块使用,synchronized后根括号,括号里是变量,这样,一次只能有一个线程进入该代码块,此时线程获得的是成员。如:public object synMethod(Object a1){ synchronized(a1){//一次只能有一个线程进入}}
③synchronized后面括号里是一对象,此时,线程获得的是对象锁,如果线程进入,则得到当前对象锁,那么别的线程在该类上所有对象上的任何操作都不能进行。
④synchronized后面括号里是类,此时线程获得的是对象锁。如果线程进入,则线程在该类中所有操作不能进行,包括静态变量和静态方法。
2、wait():使当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁,直到其他线程调用此对象的notify()或notifyAll()方法,当前线程被唤醒。
3、notifyALL():用于唤醒当前对象上的等待进程,noyify()是唤醒单个线程,而notifyAll()是唤醒所有的线程。
4、run():当通过实现Runnable接口来创建线程时,启动线程会使得run()方法在那个独立之学那个的线程中被调用。
5、start():start()会导致run()方法被调用,run()方法中的内容称为线程体,它就是这个线程需要执行的工作。

  • 具体代码

生产者

package 生产者消费者;

import java.util.LinkedList;


public class producer implements Runnable{

	    private int id;
	    
	    private storage storage;
          
	    private storage sarr[];
	    
	    private int n;

	    public producer (storage sarr[],int n){
	          this.sarr=sarr;
	          this.n=n;

	    }
	    
	    public void run(){
	        while(true){
	            try{
	            	if(n==1) {
	            		storage=sarr[0];
	            		storage.produce(storage);
	            	}
	            	else if(n>1) {
	            		storage=new storage();
	            		storage.produce(sarr, n);
	            	}
	                Thread.sleep(1000);
	            }catch (InterruptedException e){
	                e.printStackTrace();
	            }
	        }
	    }
}

消费者

package 生产者消费者;

public class consumer implements Runnable{
	  private int id;
	    
	    private storage storage;
        
	    private storage sarr[];
	    
	    private int n;

	    public consumer (storage sarr[],int n){
	          this.sarr=sarr;
	          this.n=n;
	    }
	    
	    public void run(){
	        while(true){
	            try{
	            	if(n==1) {
	            		storage=sarr[0];
	            		storage.consume(storage);
	            	}
	            	else if(n>1) {
	            		storage=new storage();
	            		storage.consume(sarr, n);
	            	}
	                Thread.sleep(1000);
	            }catch (InterruptedException e){
	                e.printStackTrace();
	            }
	        }
	    }
}

缓冲区

package 生产者消费者;

import java.util.LinkedList;

public class storage {
    
    private static int MAX_SIZE = 10;// 仓库容量
   
    // private int id=1;  //仓库id
   
    private LinkedList<Object> list = new LinkedList<>();    // 仓库存储的载体
    
    /*public int getId() {   //获取仓库号
    	return id;
    }*/
    
    public LinkedList<Object> returnList() {
    	return list;
    }
    
    public int returnSize() {
    	return MAX_SIZE;
    }
    
    public storage(){
	    
    }
    
   /* public storage(int id){
	    this.id=id;
    }*/
    
    
    public void produce(storage sarr[],int n) {//多缓冲区
		  int i=0;
		  storage storage=sarr[0];
			for(i=0;i<n;i++) {
				LinkedList<Object> list=sarr[i].returnList();
				if(list.size() + 1 <MAX_SIZE) {//缓冲区未满
					storage=sarr[i];
					break;
				}
			}
			if(i==n) {//所有缓冲区均满
		        storage=sarr[0];
			}
		  
	    	LinkedList<Object> list=storage.returnList();
	        synchronized (list) {
	            while (list.size() + 1 > 10) {
	                System.out.println("【生产者" + Thread.currentThread().getName()
			                + "】仓库已满");
	                try {
	                    list.wait();
	                } catch (InterruptedException e) {
	                    e.printStackTrace();
	                }
	            }
	            list.add(new Object());
	            System.out.println("【生产者" + Thread.currentThread().getName()
	                    + "】生产一个产品,仓库["+i+"]现库存" + list.size());
	            list.notifyAll();
	        }
	    }
    

    public void produce(storage storage ) {//单缓冲区
    	//LinkedList<Object> list=storage.returnList();
        synchronized (storage.list) {
            while (storage.list.size() + 1 > 10) {
                System.out.println("【生产者" + Thread.currentThread().getName()
		                + "】仓库已满");
                try {
                	storage.list.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            storage.list.add(new Object());
            System.out.println("【生产者" + Thread.currentThread().getName()
                    + "】生产一个产品,现库存" + storage.list.size());
            storage.list.notifyAll();
        }
    }
    

    public  void consume(storage sarr[],int n) {//多缓冲区
	    int i=0;
	    storage storage=sarr[0];
		for(i=0;i<n;i++) {
			LinkedList<Object> list=sarr[i].returnList();
			if(list.size()>=0) {
				storage=sarr[i];
				break;
			}
		}
		if(i==n) {
			 storage=sarr[0];
		}
    	//LinkedList<Object> list=storage.returnList();
        synchronized (storage.list) {
            while (storage.list.size() == 0) {
                System.out.println("【消费者" + Thread.currentThread().getName() 
						+ "】仓库为空");
                try {
                	storage.list.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            storage.list.remove();
            System.out.println("【消费者" + Thread.currentThread().getName()
                    + "】消费一个产品,仓库["+i+"]现库存" + storage.list.size());
            storage.list.notifyAll();
        }
    }
    
    public  void consume(storage storage) {
    	//LinkedList<Object> list=storage.returnList();
        synchronized (storage.list) {
            while (storage.list.size() == 0) {
                System.out.println("【消费者" + Thread.currentThread().getName() 
						+ "】仓库为空");
                try {
                	storage.list.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            storage.list.remove();
            System.out.println("【消费者" + Thread.currentThread().getName()
                    + "】消费一个产品,现库存" + storage.list.size());
            storage.list.notifyAll();
        }
    }

}

main函数

package 生产者消费者;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;


public class main {
	
	  private static storage []sarr=new storage[10];
	  
	  public static void electsence() {
	    	System.out.println("1.单生产者单消费者单缓冲区");
	    	System.out.println("2.多生产者多消费者单缓冲区");
	    	System.out.println("3.多生产者多消费者多缓冲区");

	    	System.out.println("请选择问题应用场景:");
	    	Scanner scan = new Scanner(System.in);
	    	int choice=scan.nextInt();
	    	
	    	switch(choice) {
	    	case 1:sence1();break;
	    	case 2:sence2();break;
	    	case 3:sence3();break;
	    	}
	    }
	    public static void sence1() {
	    	System.out.println("================单生产者单消费者单缓冲区================\n");
	   
	    	sarr[0]=new storage();
	        Thread p1 = new Thread(new producer(sarr,1));
	        Thread c1 = new Thread(new consumer(sarr,1));
	        p1.start();
	        c1.start();
	    }
	    
	    public static void sence2() {
	    	System.out.println("================多生产者多消费者单缓冲区================\n");
	    	sarr[0]=new storage();
	    	System.out.println("请输入生产者个数:");
	    	int pnum=0;
	    	while(true) {
	    	Scanner scan=new Scanner(System.in);
	    	pnum=scan.nextInt();
	    	if(pnum<=1) {
	          System.out.println("输入生产者数不可小于等于1!请重新输入:");
	    	}
	    	else break;
	    	}
	    	
	    	System.out.println("请输入消费者个数:");
	    	int cnum=0;
	    	while(true) {
	    	Scanner scan=new Scanner(System.in);
	    	cnum=scan.nextInt();
	    	if(cnum<=1) {
	          System.out.println("输入消费者数不可小于等于1!请重新输入:");
	    	}
	    	else break;
	    	}
	    	
	    	for(int i=0;i<pnum;i++) {
	    		Thread p=new Thread(new producer(sarr,1));
	    		p.start();
	    	}
	    	
	    	for(int j=0;j<cnum;j++) {
	    		Thread c=new Thread(new consumer(sarr,1));
	    		c.start();
	    	}
	    }
	    public static void sence3() {
	    	System.out.println("================多生产者多消费者多缓冲区================\n");
	    	System.out.println("请输入生产者个数:");
	    	int pnum=0;
	    	while(true) {
	    	Scanner scan=new Scanner(System.in);
	    	pnum=scan.nextInt();
	    	if(pnum<=1) {
	          System.out.println("输入生产者数不可小于等于1!请重新输入:");
	    	}
	    	else break;
	    	}
	    	
	    	System.out.println("请输入消费者个数:");
	    	int cnum=0;
	    	while(true) {
	    	Scanner scan=new Scanner(System.in);
	    	cnum=scan.nextInt();
	    	if(cnum<=1) {
	          System.out.println("输入消费者数不可小于等于1!请重新输入:");
	    	}
	    	else break;
	    	}
	    	
	    	System.out.println("请输入缓冲区个数:");
	    	int snum=0;
	    	while(true) {
	    	Scanner scan=new Scanner(System.in);
	    	snum=scan.nextInt();
	    	if(snum<=1) {
	          System.out.println("输入缓冲区数不可小于等于1!请重新输入:");
	    	}
	    	else break;
	    	}
	    	
	    	
	    	/*List<Storage> list = new ArrayList<Storage>();
	    	for(int i=0;i<snum;i++) {
	    		Storage test = new Storage();
	    		test.setId(i);
	    		list.add(test);
	    	}*/
	    	for(int i=0;i<snum;i++) {
	    		sarr[i]=new storage();
	    	}
	    	
	    	for(int j=0;j<pnum;j++) {
	    		Thread p=new Thread(new producer(sarr,snum));
	    		p.start();
	    	}
	    	
	    	for(int j=0;j<cnum;j++) {
	    		Thread c=new Thread(new consumer(sarr,snum));
	    		c.start();
	    	}
	    }
	
	   
	
	
	  public static void main(String[] args) {
		  electsence();
	  }
}
  • 运行结果

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

  • 10
    点赞
  • 64
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值