多线程多生产多消费问题以及解决

来源:互联网 发布:ubuntu 16.04安装 分区 编辑:程序博客网 时间:2024/04/30 01:06

多生产多消费

之前的代码针对一个生产一个消费问题可以解决同步问题。但不适应与多个生产与多个消费的问题。

package cn.java.thread.communication;//在set()和get()方法上加了synchronized后会出现连续生产或者消费的问题public class Resource {private String name;private int count;private boolean flag;//提供了商品赋值的方法。public synchronized void set(String name) {  if(flag)//有资源try {wait();    } catch (InterruptedException e) {e.printStackTrace();}this.name=name;   //count++;System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name+" "+count);  flag =true;notify();}//提供一个商品获取的方法public synchronized void get(){ if(flag)System.out.println(Thread.currentThread().getName()+"...消费者..."+this.name+" "+count);  flag=false;notify();try {wait();  } catch (InterruptedException e) {e.printStackTrace();}}}
开启多个消费、生产的线程后,会出现重复生产,重复消费的问题。原因是多个生产者或消费者在wait()后会唤醒己方的线程,因为使用的是if语句判断,线程被唤醒后不会再判断标记,会出现连续生产和连续消费的问题,所以判断要用while循环

public synchronized void set(String name) {  while(flag)//有资源try {wait();    } catch (InterruptedException e) {e.printStackTrace();}this.name=name;   //count++;System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name+" "+count);  flag =true;notify();}//提供一个商品获取的方法public synchronized void get(){ while(flag)System.out.println(Thread.currentThread().getName()+"...消费者..."+this.name+" "+count);  flag=false;notify();try {wait();  } catch (InterruptedException e) {e.printStackTrace();}}
但是运行时发现又会出现死锁现象,这是因为notify()的不确定性造成的,因为可能会唤醒本方的线程,造成消费或生产的线程都进入等待状态,此时就会死锁,所以在唤醒时要确保唤醒己方的线程,使用notifyAll()。

package cn.java.thread.communication;//在set()和get()方法上加了synchronized后会出现连续生产或者消费的问题public class Resource {private String name;private int count;private boolean flag;//提供了商品赋值的方法。public synchronized void set(String name) {  while(flag)//有资源try {wait();    } catch (InterruptedException e) {e.printStackTrace();}this.name=name;   //count++;System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name+" "+count);  flag =true;notifyAll();}//提供一个商品获取的方法public synchronized void get(){ while(flag)System.out.println(Thread.currentThread().getName()+"...消费者..."+this.name+" "+count);  flag=false;notifyAll();try {wait();  } catch (InterruptedException e) {e.printStackTrace();}}}
虽然使用了while()和notifyAll()解决了重复出现消费和生产以及死锁等问题,但是由于notifyAll()的不确定唤醒使得每次都可能唤醒本方的消费或生产线程,使得需要多判断一次,所以效率低,JDK1.4无法解决这个问题。

JDK1.5提供了Lcok接口,先前的监视器方法(waitnotifynotifyAll)都是和锁对象绑定的,Lock接口的出现使监视器方法从锁对象中分离出来,更加的面向对象,现在可以通过Lock的newCondition的方法使用这些监视器方法,更加的灵活。

package cn.java.thread.communication;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class Resource {private String name;private int count;private boolean flag;private Lock lock =new ReentrantLock();private Condition producer_con= lock.newCondition();private Condition consumer_con= lock.newCondition();//提供了商品赋值的方法。public  void set(String name) {  //t0 t1lock.lock();try{while(flag){//有资源try {producer_con.await();   // t1} catch (InterruptedException e) {e.printStackTrace();}}this.name=name;   //count++;System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name+" "+count);  //t0-面包1 t0-面包2 t1-面包3flag = true;consumer_con.signalAll();}finally{lock.unlock();}}//提供一个商品获取的方法public  void get(){  //t2 t3lock.lock();try{while(flag){ //有资源System.out.println(Thread.currentThread().getName()+"...消费者..."+this.name+" "+count);  //t2-面包1、flag=false;producer_con.signalAll();}try {//没有资源consumer_con.await(); //t2 t3 } catch (InterruptedException e) {e.printStackTrace();}}finally{lock.unlock();}}}
JDK文档中向我们提供了Condition对象的实例,跟上面的例子不同的是它的资源池的容量是随时变化的。
package cn.java.thread.communication;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class BoundedBuffer {final Lock lock = new ReentrantLock();final Condition notFull = lock.newCondition();//相当于生产者final Condition notEmpty = lock.newCondition();//消费者final Object[] items = new Object[100];int putptr, takeptr, count;//这里定义两个指针分别从头开始存和取public void put(Object x) throws InterruptedException {lock.lock();try {while (count == items.length) //资源池满等待notFull.await();items[putptr] = x; //数组指针自增System.out.println(Thread.currentThread().getName()+"....put方法...."+x); //如果满了则指针从头开始,++putptr写的很巧,每次向容器存入对象后,指针先自增再判断容器是否已经满if (++putptr == items.length)putptr = 0; ++count; //记录当前资源池资源个数notEmpty.signal(); //唤醒消费来消费资源} finally {lock.unlock();}}public Object take() throws InterruptedException {lock.lock();try {while (count == 0) //容器空消费者就等待notEmpty.await();Object x = items[takeptr];System.out.println(Thread.currentThread().getName()+"...take方法..."+x);//每次从容器取出对象后都要指针自增,判断是否到数组尾重头取if (++takeptr == items.length)takeptr = 0;--count;notFull.signal();return x;} finally {lock.unlock();}}}



0 0