黑马程序员——生产者和消费者问题

来源:互联网 发布:徐州淘宝产业链 编辑:程序博客网 时间:2024/06/05 03:07

         生产者消费者问题是学习多线程时绕不开的经典问题之一,它描述是有一块缓冲区作为共享资源,生产者可以将产品放入在共享空间,消费者则可以从该共享空间中消耗资源,在这个问题中要保证以下几点:

(1)同一时间内只有一个生产者进行生产。

(2)同一时间只有一个消费者进行消费。

(3)生产者生产时消费者不能消费。

(4)消费者消费时生产者不能生产。

(5)共享空间空时消费者不能继续消费。

(6)共享空间满时生产者不能继续生产。

一、wait()/notify()方法

wait()/notify()方法是基类Object的两个方法,也就意味着所有Java类都会拥有这两个方法,这样,我们就可以为任何对象实现同步机制。

wait()方法:当缓冲区已满、空时,生产者/消费者线程停止自己的执行,放弃锁,使自己处于等待状态,让其他线程执行。

notify()方法:当生产者/消费者向缓冲区放入/取出一个产品时,向其他等待的线程发出可执行的通知,同时放弃锁,使自己处于等待状态。

class Resource{  private String name;  private int counts=0; public boolean flag=false; //是否有资源的判断标识      //生产函数。 public synchronized void set(String name){  //判端是否有资源,有就放弃执行权,没有就生产   if(flag){  try {     wait();   } catch (InterruptedException e) {     e.printStackTrace();  }   }   this.name=name;  counts++;  System.out.println(Thread.currentThread().getName()+":"+name+"======="+counts);  this.flag=true;//生产后将资源标识置为真  notify();//唤醒线程  }         //消费函数。    public synchronized void out(){     //判端是否有资源,有就消费掉,没有就放弃执行权       if(!flag){       try {        wait();       }       catch (InterruptedException e) {         e.printStackTrace();       }      }      System.out.println(Thread.currentThread().getName()+":"+name+".................."+counts);      this.flag=false;//消费后将标识置为假       notify();//唤醒线程     }}      //生产者类,实现Runnable接口class Producer implements Runnable{       private Resource res;      public Producer(Resource res){         this.res=res;      }      @Override       public void run() {         while(true){            res.set("包子");          }       }}          //消费者类,实现Runnable接口class Consumer implements Runnable{       private Resource res;      public Consumer(Resource res){            this.res=res;       }       @Override      public void run() {          while(true){             res.out();          }      }}              public class ProducerConsumer {       public static void main(String[] args) {       Resource res=new Resource();       Producer pro=new Producer(res);       Consumer con=new Consumer(res);       new Thread(pro).start();//生产者1线程启动        new Thread(pro).start();//生产者2线程启动              new Thread(con).start();//消费者1线程启动              new Thread(con).start();//消费者2线程启动        }}


 

二、await()/signal()方法

JDK5.0之后,Java提供了更加健壮的线程处理机制,包括同步、锁定、线程池等,它们可以实现更细粒度的线程控制。await()signal()就是其中用来做同步的两种方法,它们的功能基本上和wait() / nofity()相同,完全可以取代它们,但是它们和新引入的锁定机制Lock直接挂钩,具有更大的灵活性。通过在Lock对象上调用newCondition()方法,将条件变量和一个锁对象进行绑定,进而控制并发程序访问竞争资源的安全。下面来看代码:

import java.util.concurrent.locks.*;//生产者和消费者共享的资源class Resource{                      private String name;private int counts=0;private Lock lock=new ReentrantLock();private Condition condition_pro=lock.newCondition();private Condition condition_con=lock.newCondition();public boolean flag=false; //是否有资源的判断标识//生产函数。public void set(String name){lock.lock();//加锁//判端是否有资源,有就放弃执行权,没有就生产try {while(flag){condition_pro.await();}this.name=name;counts++;System.out.println(Thread.currentThread().getName()+":"+name+"======="+counts);this.flag=true;//生产后将资源标识置为真condition_con.signal();} catch (InterruptedException e) {e.printStackTrace();}finally{lock.unlock();//解锁}}//消费函数。public void out(){lock.lock();//判端是否有资源,有就消费掉,没有就放弃执行权try {while(!flag){condition_con.await();}System.out.println(Thread.currentThread().getName()+":"+name+".................."+counts);this.flag=false;//消费后将标识置为假condition_pro.signal();//唤醒线程} catch (InterruptedException e) {e.printStackTrace();}finally{lock.unlock();}}}//生产者类,实现Runnable接口class Producer implements Runnable{private Resource res;public Producer(Resource res){this.res=res;}@Overridepublic void run() { while(true){res.set("包子");}}}//消费者类,实现Runnable接口class Consumer implements Runnable{private Resource res;public Consumer(Resource res){this.res=res;}@Overridepublic void run() {while(true){res.out();}}}public class ProducerConsumer {public static void main(String[] args) {Resource res=new Resource();Producer pro=new Producer(res);Consumer con=new Consumer(res);new Thread(pro).start();//生产者1线程启动new Thread(pro).start();//生产者2线程启动new Thread(con).start();//消费者1线程启动new Thread(con).start();//消费者2线程启动}}

这种多生产者和消费者JDK1.5升级版,使用Lock替代了synchrnized,Condition替代了Object监视器方法。好处是一个锁可以对应多个Condition对象,值得注意的是释放锁的工作一定要执行。

0 0
原创粉丝点击