[Java]多线程之生产者消费者

上一篇多线程写完好久了,今天补上顺便回忆下

前面提到死锁的产生,这里来解决下,换个demo

 

购票时会有退票,包子有销售也会有生产,所以提一个实际中的线程问题,经典的生产者消费者

生产者、消费者实现runnable接口,由于双方使用同一个资源包子,可以单独拿出来,写上两个属性,价格和名字

现在生产者要生产包子,相当于给资源--包子的属性赋值,贴上标签,说明这个生产好了,消费者可以拿去。

然后消费者要来拿,此时baozi在生产者里是一个成员变量,如何让消费者拿到?其实就是如何共享数据?让他们使用构造方法传递同一个引用,使用同一个引用就共享了同一个数据。

 

 

接下来,要在run里拿到包子,输出一下

至此生产和消费框架搭建完毕,去demo里启动线程

生产者消费者都是实现接口的方式,这边首先要分别实例化一个对象出来再去启动线程。因为生产者和消费者都是带参的,没有默认的无参了,这边实例化的时候也必须带上

这个时候走起有问题,一直是消费者被调用,但是没有包子

为啥,因为生产者的run方法内一直在new包子,而不是上面的引用传过来的,这样子生产者和消费的包子其实不是同一个,没有实现共享,去掉new这一行

OK~现在依然有问题,因为在生产里,实际上有两步,名字和价格是分开的,这就有可能在命名后被挂起,消费者拿到的是没有价格的包子,或者在有多种包子的时候,出现错乱

再添加一种包子

 

看看运行结果

 

给生产者消费者都上锁,注意锁的选举,必须是同一把锁,这里有现成的对象baozi

再走起,还会出问题,有可能拿到是空的,因为有可能是消费者先走的,这个时候还没有生产。

这个时候同步机制无法解决,他只能解决非原子操作带来的问题,现在就需要进程间通信来搞定~

三个方法,Wait()  Notify()  notifyAll()

怎么实现通知机制的呢,在走到notify的时候,把锁释放掉,另外一个线程就能进来了

他们都在object类下面,虽然线程的实现依赖于thread类,两个线程间如何实现通信的?是因为拥有同一把锁,这一把锁可以是任何一个对象,任何对象都有锁,所以这些具体的通信方法应该是基于顶层的object,而不能局限在thread

 

要解决这种问题:最优的解决方案是:

 * 生产者来说:  看看有没有包子,有的话就等待,没有的话才生产,生产完之后发出通知

 * 消费者来说:  看看有没有包子,有的话就买,没有的话就等待。买了之后就发出通知

 

给包子再加一个属性,flag标志位,默认为false,在生产者里面判断下有没有包子

给生产者和消费者要加上flag,一定要注意,通过flag判断有没有包子必须synchronized()锁里面,否则在判断flag的时候,有可能被挂起,因为这不是原子操作,这会导致后面的进程间通信的几个方法出现异常。

对于消费者来说,有包子才消费,消费了还要通知生产者,生产者还在等待;没有包子就等待

 

对于生产者来说,有包子则等待,等待消费者消费后来的通知;没有包子则生产,生产好了通知消费者有包子了,消费者还在等待

 

OK,走起,至此这个例子基本搞定

 

完整代码:

生产者

public class Producer implements Runnable {
    Baozi baozi;
	int x =0;
    public Producer(Baozi b){
    	baozi = b;
    }
	@Override
	public void run() {
	   while(true){
		 synchronized (baozi) {
		 if(!baozi.flag){
		   if(x%2==0){
				baozi.name="天津狗不理";
				baozi.price=10;
			}
			else{
				baozi.name="澳门猪扒包";
				baozi.price=20;
			}
		   x++;	
			//没有包子,生产,此时就应该有了,改为true
			baozi.flag=true;
			 //通知消费者有包子
		    baozi.notify();	 
			System.out.println("Producer.sell " +baozi.name+"  "+baozi.price);
		 }else{
			//flag为true,说明有包子,此时要等待消费者来消费
				try {				 
					baozi.wait();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
		 }
		 }
	   }       
	}
}


消费者

 

public class Customer implements Runnable {
    Baozi baozi;
	public Customer(Baozi b){
    	baozi = b;
    }
	@Override
	public void run() {	
	 while (true) {
	  synchronized (baozi) {
		if(baozi.flag){
		  System.out.println("Customer got "+ baozi.name+"  "+baozi.price  );
		  //消费了,置为false
		  baozi.flag=false;
		  //给生产者通知,因为你是有才来消费
          //而生产者有则是等待,不通知一直等
	      baozi.notify();	
		}else{
			try {
				baozi.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	  }
	 }
	}
}


资源池:

public class Baozi {
	 String name;
	 int    price;
	 boolean flag=false;
}


main:

public class MyPandCDemo {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
        Baozi baozi =new Baozi();
		//需要带参来实例化
		Producer producer = new Producer(baozi);
		Customer customer = new Customer(baozi);
			
		Thread thread1 = new Thread(producer, "Producer");
		Thread thread2 = new Thread(customer, "Customer");

		thread1.start();		
		thread2.start();
	}
}


 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值