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

来源:互联网 发布:访问网站出现 php探针 编辑:程序博客网 时间:2024/06/05 04:51
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
原创粉丝点击