线程间通信 wait()/notify() 用例

考虑一个生产者/消费者模型。

 

商品类Goods 

class Goods { 

         private  String name; 

       public  Goods(String name)  { this.name =name; } 

      public   String  toString()  {  return "Goods[" + name + ']';  }

}

 

商品容器类GoodsStatck 

class GoodsStatck{ 


   private  Goods[]buffer;

   int point =-1;

   int size; 


   GoodsStatck (int size) {  this.size = size;  buffer = new Goods[size];   } 


   public synchronized int getPoint() { return this.point; }

 

   public synchronized Goods pop() {

       if (point0) {

           return null;

       }

       Goods goods = buffer[point];

       buffer[point] = null;

       point--;

       return goods;

   }

 

   public synchronized boolean push(Goods goods){

       if (point= size - 1) {

           return false;

       }

       point++;

       buffer[point] = goods;

          return true;

   }

}

 

生产者类Producer 

class Producer implements Runnable{ 


   private GoodsStatck  goodsStatck;

    private   String name; 


    Producer(String name, GoodsStatck  goodsStatck) {

       this.name = name;

       this.goodsStatck = goodsStatck;

   }

  

   public void run(){

       while (true) {

           synchronized (this.goodsStatck) {

               Goods goods = new Goods("No-" + (this.goodsStatck.getPoint() +1));

               boolean result =this.goodsStatck.push(goods);

               if (result) {

                    System.out.println(name + " produce : " + goods);

               }

               else{

                    System.err.println("Error! The stack is full");

               }

           }

       }

   }

}

 

 

消费者类Producer 

class Consumer implements Runnable{ 


   private GoodsStatck goodsStatck;

   private String name; 


   Consumer(String name, GoodsStatck goodsStatck) {

       this.name =name;

       this.goodsStatck =goodsStatck;

   }


   public void run(){

       while (true) {

           Goods goods =this.goodsStatck.pop();

           if (goods !=null) {

               System.out.println(name + " get : " + goods);

           }else {

               System.err.println("Error! There is no goods in stack ");

           }

       } 

   }

}

 

测试程序  

       GoodsStatck goodsStatck = new GoodsStatck(2);

       Producer producer1 = new Producer("producer-1",goodsStatck);

       Producer producer2 = new Producer("producer-2",goodsStatck);

       Consumer consumer1 = new Consumer("consumer-1",goodsStatck);

       Consumer consumer2 = new Consumer("consumer-2",goodsStatck); 

       new Thread(producer1).start();

       new Thread(producer2).start();

       new Thread(consumer1).start();

       new Thread(consumer2).start(); 

 

可能出现以下输出:

Error!The stack is full  

Error!There is no goods in stack

 

即在push的时候会遇到容器GoodsStatck已满,pop的时候遇到容器GoodsStatck为空的情况。

 

要改变这种情况,必须使用wait()/notify(),即将GoodsStatck的pop()、push() 修改如下:

 

   public synchronized Goods pop() {

       this.notifyAll();

       while (point0) {

           try {

               this.wait();

           }catch (InterruptedException ex) { throw new RuntimeException(ex); }

       }

       Goods goods = buffer[point];

       buffer[point] = null;

       point--;

       return goods;

   }

 

   public synchronized boolean push(Goods goods){

       this.notifyAll();

       while (point= size - 1) {

           try {

               this.wait();

           }catch (InterruptedException ex) { throw new RuntimeException(ex); }

       }

       point++;

       buffer[point] = goods;

       return true;

   }

 

这样在遇到容器GoodsStatck为空或满的情况时(while循环中),线程将放弃锁(GoodsStatck.this)阻塞,直到满足条件。使用时候注意:

 

1. 先唤醒其他线程,再放弃自己的锁,即先notify()/notifyAll(),再wait()

2. wait() 方法必须放在while循环中,不能放在if条件中

3. 一般情况下,notifyAll() 优于notify()


可以用 java.util.concurrent包中阻塞队列 BlockingQueue(interface) 实现 ( LinkedBlockingDeque(class), ArrayBlockingQueue  (class) ,  PriorityBlockingQueue  (class)