(52)多个生产者多个消费者出现的问题,解决方式synchronized方法和Lock方法

public class Resoure {

    private String name;
    private int count =1;
    private boolean flag=false;
    public synchronized void set(String name) {
        if(flag) {
            try {
                this.wait();
            } catch (Exception e) {

            }
        }
         this.name=name+"----"+count++;
         System.out.println(Thread.currentThread().getName()+"生产者"+this.name);
          flag=true;
          this.notify();
        }


    public synchronized void out() {
     if (!flag) {
            try {
            this.wait();
        } catch (Exception e) { }

        }   
         System.out.println(Thread.currentThread().getName()+"消费者"+this.name);
         flag=false;
          this.notify();
       }

    }
public class Producer implements Runnable {

    private Resoure res;
    Producer(Resoure res){
        this.res=res;

    }
    public void run() {
        while(true) {
            res.set("+商品+");
        }
    }
}
public class Consumer implements Runnable {
    private Resoure res;
    Consumer(Resoure res){
        this.res=res;

    }
    public void run() {
        while(true) {
            res.out();
        }
    }
}
public class ProduceConsumerDemo {
    public static void main(String[] args) {
        Resoure  r=new Resoure();
        Producer pro=new Producer(r);
        Consumer con=new Consumer(r);
        Thread t1=new Thread(pro);
        Thread t2=new Thread(con);
        t1.start();
        t2.start();

    }
}

两个生产者两个消费者,这个程序会出现问题:
t1线程开启,flag=false,所以生产了一个数据,将flag置为true,唤醒该对象的其他线程,t1可能还有执行权,所以继续执行,flag=true,等待,放弃资格。
其他当前对象的t2,t3,t4都有可能抢到资源。假设t2抢到了资源,因为flag是个共享资源,所以flag为真,等待放弃资格。
t3线程获得资格,if判断失败,即有数据可消费,所以消费,flag=false
唤醒t1。(正常消费),t3可能还可以执行,但if判断失败,所以等待,放弃执行资格.
假设此时t4此时获得了执行权,因为if判断失败,等待,放弃执行资格。
就只剩t1有执行资格,T1有执行资格,所以生产一个数据,flag=true,唤醒该对象的其他线程,t1仍有执行权,if判断失败放弃资格。此时,它唤醒的是t2(才会出现两个生产打印,只消费第一个情况),t2获取资格,此时,只有t2可以获得执行权,所以应从刚才等待的下一条语句开始执行,所以又生产了一个数据。
生产两个数据,第一个生产的数据被覆盖,输出的就是第二个数据。
为什么会出现这种情况呢?
原因是t1生产完后,将flag=true,理应t2不能生产,但是t1生产完后,可以唤醒t2,就不再判断if(flag),直接生产.
修改方法:
让这种情况消失需要修改的地方是将if(flag)改为while(flag),即使醒了,因为while,也会判断flag.
但是呢,这样做,会造成全睡的情况,全部等待,刚才就是只有t2获得资格,但是flag判断失败,所以全没资格了。但不是死锁。
死锁是锁中有异锁。
继续修改:
唤醒所有,将this.notify(),改为this.notifyall(),这样t2,t3,t4全唤醒,t2中while判断失败,失去资格。t3,t4虽然会都醒,但是只能一个线程有执行权,假设t3获得执行权,while(!flag)假,消费数据,
然后flag=false,t4又没有执行条件了。
通过Lock对此程序进行修改和以上的修改,就是表达方式不同

import java.util.concurrent.locks.*;


public class Resoure {

    private String name;
    private int count =1;
    private boolean flag=false;
    private Lock lock=new ReentrantLock();
    private Condition condition=lock.newCondition();
    public void set(String name)throws InterruptedException {
        lock.lock();
        try {
        while(flag) 
            condition.await();
         this.name=name+"----"+count++;
         System.out.println(Thread.currentThread().getName()+"生产者"+this.name);
          flag=true;
          condition.signalAll();

        }
        finally {
            lock.unlock();
        }

    }   


    public  void out()throws InterruptedException {
        lock.lock();
        try {
            while (!flag) 
                condition.await();
             System.out.println(Thread.currentThread().getName()+"消费者"+this.name);
             flag=false;
             condition.signalAll();

        }
        finally {
            lock.unlock();
        }
    }
}

上面的方法无论是signalAll,还是notifyAll都是唤醒其他等待的,可以支持多个相关的 Condition 对象,所以生产者可以唤醒消费者,互相唤醒。
**jdk1.5中提供了多线程升级解决方案。
将同步synchronized替换成现实Lock操作。
将Object中的wait,notify,notifyAll替换成Condition对象,该对象可以Lock锁,进行获取。**

import java.util.concurrent.locks.*;


public class Resoure {

    private String name;
    private int count =1;
    private boolean flag=false;
    private Lock lock=new ReentrantLock();
    private Condition condition_pro=lock.newCondition();
    private Condition condition_con=lock.newCondition();
    public void set(String name)throws InterruptedException {
        lock.lock();
        try {
        while(flag) 
            condition_pro.await();
         this.name=name+"----"+count++;
         System.out.println(Thread.currentThread().getName()+"生产者"+this.name);
          flag=true;
          condition_con.signalAll();

        }
        finally {
            lock.unlock();
        }

    }   


    public  void out()throws InterruptedException {
        lock.lock();
        try {
            while (!flag) 
                condition_con.await();
             System.out.println(Thread.currentThread().getName()+"消费者"+this.name);
             flag=false;
             condition_pro.signalAll();

        }
        finally {
            lock.unlock();
        }


    }
}

这是API例子

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值