您的位置:首页 > 编程语言 > Java开发

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

2015-06-07 22:50 483 查看
上一篇多线程写完好久了,今天补上顺便回忆下

前面提到死锁的产生,这里来解决下,换个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();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: