1.多线程-线程间通信-多生产者多消费者问题

 

多生产者和多消费者。等待唤醒机制。

产生了两个问题:

    1.出现了多次连续生产,未消费,或者一个商品被消费多次。

        解决:必须要--------每一个被唤醒的线程判断一次标记,所以将if判断改为while判断。 

    2.出现了死锁

        本方唤醒了本方,导致了所有的线程都等待了。

        解决方式就是:唤醒所有等待的线程。这样既唤醒了本方也唤醒对方。

        虽然解决了多生产消费的问题,但是有些低效。

 

解决方法一: 唤醒所有等待的线程

class Resource{
    private String name;//定义一个商品都有名字。
    private int count = 1; //定义一个商品的编号。
    private boolean flag = false;//定义用来判断是否有商品的标记。
    public synchronized  void set(String name){
        while(flag)
            try{wait();}catch(Exception e){}//t1,t2
        this.name = name+"--"+count;//蛋糕1  蛋糕2 蛋糕3
        count++;
         
        System.out.println(Thread.currentThread().getName()+"---生产了,"+this.name);
                //生产蛋糕1 生产蛋糕2 生产蛋糕3        
        flag = true; //将标记改为true。
        notifyAll();//唤醒等待的线程。 
    }
        
    public synchronized void get()//{
        while(!flag)
            try{wait();}catch(Exception e){}//t3.t4
        System.out.println(Thread.currentThread().getName()+"-------消费了....."+this.name);//消费蛋糕1
        flag = false;
        notifyAll();
    }
}
 
//定义生产者的任务。
class Producer implements Runnable{
    private Resource r;
    Producer(Resource r){
        this.r = r;
    }
    public void run(){
        while(true){
            r.set("蛋糕");
        }
    }
 
}
 
 
//定义消费者的任务。
class Consumer implements Runnable{
    private Resource r;
    Consumer(Resource r){
        this.r = r;
    }
    public void run(){
        while(true){
            r.get();
        }
    }
}
 
 
class ThreadDemo_Producer_Consumer2 {
    public static void main(String[] args) {
        Resource r = new Resource();
        Producer pro = new Producer(r);
        Consumer con = new Consumer(r);
         
        //创建两个生产者线程。
        Thread t1 = new Thread(pro);
        Thread t2 = new Thread(pro);
        //创建两个消费者线程。
        Thread t3 = new Thread(con);
        Thread t4 = new Thread(con);
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}


解决方法二:使用Lock锁对象和Condition监听对象

根据jdk1.5 版本的特性,创建一个锁对象。比同步的隐式锁操作要更加的面向对象。提供了显示的锁操作。

通过lock锁获取监视器方法对象。Condition 负责生产者的监视操作。

创建一个监视器方法对象。负责消费者的监视操作。

    解决了低效的问题



import java.util.concurrent.locks.*;
 
class Resource{
    //定义一个商品都有名字。
    private String name;
    //定义一个商品的编号。
    private int count = 1;
     
    //定义用来判断是否有商品的标记。
    private boolean flag = false;
     
    //根据jdk1.5 版本的特性,创建一个锁对象。比同步的隐式锁操作要更加的面向对象。提供了显示的锁操作。
    final Lock lock = new ReentrantLock();//互斥锁。
     
    //通过lock锁获取监视器方法对象。Condition 负责生产者的监视操作。
    final Condition producer = lock.newCondition();
     
    //再创建一个监视器方法对象。负责消费者的监视操作。
    final Condition consumer = lock.newCondition();
     
    public void set(String name)//{
        //通过锁对象进行显示的获取锁操作。
        lock.lock();//获取锁,锁的开始位置,想从哪里锁就把锁放在什么地方
        try{
            while(flag)
            try{producer.await();}catch(Exception e){}//t1,t2
            this.name = name+"--"+count;
            count++;
             
            System.out.println(Thread.currentThread().getName()+"生产了,"+this.name);
            //将标记改为true。
            flag = true;
            consumer.signal();//唤醒等待的线程。 
        }finally{
            //释放锁。
            lock.unlock();//定义在finally中,要求一定被释放。
        }
    }
 
 
    public  void get()//{
        lock.lock();
        try{
            while(!flag)
            try{consumer.await();}catch(Exception e){}//t3.t4
            System.out.println(Thread.currentThread().getName()+"--消费了."+this.name);                    //消费蛋糕1
            flag = false;
            producer.signal();
        }finally{
            lock.unlock();
        }
    }
}
 
//定义生产者的任务。
class Producer implements Runnable{
    private Resource r;
    Producer(Resource r){
        this.r = r;
    }
    public void run(){
        while(true){
            r.set("蛋糕");
        }
    }
 
}
 
 
//定义消费者的任务。
class Consumer implements Runnable{
    private Resource r;
    Consumer(Resource r){
        this.r = r;
    }
    public void run(){
        while(true){
            r.get();
        }
    }
}
 
class ThreadDemo_Producer_Consumer3 {
    public static void main(String[] args) {
        Resource r = new Resource();
        Producer pro = new Producer(r);
        Consumer con = new Consumer(r);
         
        //创建两个生产者线程。
        Thread t1 = new Thread(pro);
        Thread t2 = new Thread(pro);
        //创建两个消费者线程。
        Thread t3 = new Thread(con);
        Thread t4 = new Thread(con);
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}