【java】多线程 生产者消费者问题 共享资源区的大小 实例

生产者消费者问题包含三个成分:

1.生产者,用于提供数据   生产者类

2.消费者,用于拿走数据   消费者类

3.共享资源,就像是一个仓库,消费者把提供的数据放进去,生产者拿走数据。(用于解耦生产者和消费者的关系) 奶箱类

以下是一个实例

我们想喝牛奶但是又不想去商店买(生产者是商店,消费者是我,路径是 生产者->消费者),因此我们就选择了订奶

送奶工早上将牛奶从商店送来我手里,但是我早上又起不来那么早,难道就无法拿到牛奶了吗?

不,送奶工会将牛奶送到我家门口的奶箱,等我起床后只需要去奶箱里面拿就好了,这个过程我与送奶工并没有直接的见面(生产者与消费者没有变,但是我们两个中间多了一个中介:送奶工与奶箱,这时的路径就是:生产者->传递数据(送奶工)->共享资源(奶箱)->拿走数据(我)->消费者

而在我们的代码编写过程中,生产者->传递数据->共享资源->拿走数据->消费者,我们这样建立:

生产者类 实现Runnable接口,重写run()方法,且传入奶箱类对象【一条传入数据的路径】

消费者类 实现Runnable接口,重写run()方法,且传入奶箱类对象【一条拿走数据的路径】

奶箱类 包含表示奶箱大小,奶箱状态等的成员变量,及传入数据的方法和拿走数据的方法

测试类 建立对象并使用多线程实现

代码如下:(这里共享资源默认大小为一,只有放入与不放入) 

//奶箱类
public class Box {

	private int milk;
	private boolean state=false;定义一个成员变量表示奶箱的状态,false表示没有牛奶
	
//下面使用的存放方式是默认奶箱容量为一
	public synchronized void put(int milk) {
		
		//如果有牛奶,等待消费
		if(state) {
			try {
				wait();
			} catch (InterruptedException e) {
				// TODO 自动生成的 catch 块
				e.printStackTrace();
			}
		}
		
		//如果没有牛奶,生产牛奶
		this.milk=milk;
		System.out.println("送奶工正在送第"+milk+"瓶奶");
		//生产完毕之后修改奶箱
	    state=true;
	    notifyAll();
	}
	
	public synchronized void get() {
		/*“线程操作的wait()、notify()、notifyAll()方法只能在同步控制方法或同步控制块内调用。
		 * 如果在非同步控制方法或控制块里调用,程序能通过编译
		 * 但运行的时候,将得到 IllegalMonitorStateException 异常,并伴随着一些含糊信息,比如 ‘当前线程不是拥有者’。
		 * 其实异常的含义是 调用wait()、notify()、notifyAll()的任务在调用这些方法前必须 ‘拥有’(获取)对象的锁。*/
		//如果有牛奶,等待拿走
		if(!state) {
			//如果没有牛奶,等待生产
		try {
				wait();
			} catch (InterruptedException e) {
				// TODO 自动生成的 catch 块
				e.printStackTrace();
			}
		}
		
		//如果有牛奶,消费牛奶
		System.out.println("用户拿走第"+milk+"瓶奶");
		state=false;//牛奶被拿走
		notifyAll();
	}
	
}

//生产者类
public class Producer implements Runnable {

	private Box box;

	public Producer(Box box) {
		
		this.box=box;
		
	}

	public void run() {
		
		for(int i=1;i<=5;i++) {//通过这里定义放入奶的数量
			box.put(i);
		}
		
	}

}

//消费者类
public class Customer implements Runnable {
	
    private Box box;

	public Customer(Box box) {
		
		this.box=box;
		
	}

	public void run() {
		while(true) {//这里用无限循环的方式是因为奶箱类里面定义的get()方法含有判断
			box.get();
		} 
	}
//测试类
public class BoxDemo {

	public static void main(String[] args) {
		
		Box box=new Box();//共享数据对象
		
		Producer producer=new Producer(box);//生产者对象,使用box做参数
		Customer customer=new Customer(box);//消费者对象,使用box做参数
		
		//创建两个线程
		Thread t1=new Thread(producer);
		Thread t2=new Thread(customer);
		
		t1.start();
		t2.start();

	}

}

再对比一下下面的代码,多定义了一个size表示奶箱的大小

public class Box {

	private int milk=9;
	static final int size=3;//奶箱一次最多放入三瓶奶
	static int state=0;定义一个成员变量表示奶箱中的奶数
	
	public synchronized void put() {
		
		//如果牛奶数等于奶箱容积,等待消费
		if(state==size) {

			try {
				wait();
			} catch (InterruptedException e) {
				// TODO 自动生成的 catch 块
				e.printStackTrace();
			}
			
		}
		
		for(;state<size&&state>=0;state++) {
			
		//如果奶箱中的牛奶数小于奶箱容积,生产者继续生产并放入,每放入一瓶奶箱中的奶数量加一,直到奶数达到容积,停止放入
		System.out.println("送奶工正在送第"+milk+"瓶奶");
		milk--;
	    
	    }
		
	    notifyAll();
	    
	}
	
	public synchronized void get() {
		/*“线程操作的wait()、notify()、notifyAll()方法只能在同步控制方法或同步控制块内调用。
		 * 如果在非同步控制方法或控制块里调用,程序能通过编译
		 * 但运行的时候,将得到 IllegalMonitorStateException 异常,并伴随着一些含糊信息,比如 ‘当前线程不是拥有者’。
		 * 其实异常的含义是 调用wait()、notify()、notifyAll()的任务在调用这些方法前必须 ‘拥有’(获取)对象的锁。*/
		
		for(;state>0&&state<=size;state--) {//如果有牛奶,消费牛奶
			
			System.out.println("用户拿走奶箱中的第"+state+"瓶奶");
			
		}
		
		notifyAll();
		
		if(state==0) {
					//如果没有牛奶,等待生产
		            try {
						wait();
					} catch (InterruptedException e) {
						// TODO 自动生成的 catch 块
						e.printStackTrace();
					}
		            
		}

	}
	
}


public class Customer implements Runnable {
	
    private Box box;

	public Customer(Box box) {
		
		this.box=box;
		
	}

	public void run() {
		
		for(int i=1;i<3;i++) {//这里的i实际上是milk数除以size数
		//这个程序并不完善,没有判断当milk不能整除size时,送奶工如何送奶及用户如何拿奶
	    //这时还需要在put方法里面加一个判断
		//if(milk/size!=0)
		//size=milk%size;
			box.get();
         }
	}

}


public class Producer implements Runnable {

	private Box box;

	public Producer(Box box) {
		
		this.box=box;
		
	}

	public void run() {
		while(true) {
			box.put();
		}
		}
		

}


public class BoxDemo {

	public static void main(String[] args) {
		
		Box box=new Box();//共享数据对象
		
		Producer producer=new Producer(box);//生产者对象,使用box做参数
		Customer customer=new Customer(box);//消费者对象,使用box做参数
		
		//创建两个线程
		Thread t1=new Thread(producer);
		Thread t2=new Thread(customer);
		
		t1.start();
		t2.start();

	}

}

结果如下:

送奶工一次送三瓶奶,即共享资源大小为三 

送奶工正在送第9瓶奶
送奶工正在送第8瓶奶
送奶工正在送第7瓶奶
用户拿走奶箱中的第3瓶奶
用户拿走奶箱中的第2瓶奶
用户拿走奶箱中的第1瓶奶
送奶工正在送第6瓶奶
送奶工正在送第5瓶奶
送奶工正在送第4瓶奶
用户拿走奶箱中的第3瓶奶
用户拿走奶箱中的第2瓶奶
用户拿走奶箱中的第1瓶奶
送奶工正在送第3瓶奶
送奶工正在送第2瓶奶
送奶工正在送第1瓶奶

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老坛酸菜吃鸭子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值