使用Lock来实现生产者和消费者问题

Lock的await/singal 和 Object的wait/notify 的区别

在使用Lock之前,我们都使用Object 的wait和notify实现同步的。举例来说,一个producer和consumer,consumer发现没有东西了,等待,produer生成东西了,唤醒。

线程consumer 线程producer
synchronize(obj){ 
    obj.wait();//没东西了,等待 
}
synchronize(obj){ 
    obj.notify();//有东西了,唤醒 
}

有了lock后,世道变了,现在是:

lock.lock(); 
condition.await(); 
lock.unlock();
lock.lock(); 
condition.signal(); 
lock.unlock();

为了突出区别,省略了若干细节。区别有三点:

  1. 1. lock不再用synchronize把同步代码包装起来;
  2. 2. 阻塞需要另外一个对象condition;
  3. 3. 同步和唤醒的对象是condition而不是lock,对应的方法是await和signal,而不是wait和notify。

为什么需要使用condition呢?简单一句话,lock更灵活。以前的方式只能有一个等待队列,在实际应用时可能需要多个,比如读和写。为了这个灵活性,lock将同步互斥控制和等待队列分离开来,互斥保证在某个时刻只有一个线程访问临界区(lock自己完成),等待队列负责保存被阻塞的线程(condition完成)。

通过查看ReentrantLock的源代码发现,condition其实是等待队列的一个管理者,condition确保阻塞的对象按顺序被唤醒。

在Lock的实现中,LockSupport被用来实现线程状态的改变,后续将更进一步研究LockSupport的实现机制。

 

 

[java] view plain copy
 
  1.  package com.thread;  
  2.    
  3.  import java.util.LinkedList;  
  4.  import java.util.concurrent.locks.Condition;  
  5.  import java.util.concurrent.locks.Lock;  
  6.  import java.util.concurrent.locks.ReentrantLock;  
  7.    
  8.    
  9.  /** 
  10.   * 使用Lock来实现生产者和消费者问题 
  11.   *  
  12.   *  
  13.   * 
  14.   */  
  15.  public class ProducerConsumer {  
  16.      public static void main(String[] args) {  
  17.          Basket b = new Basket();  
  18.          Product p = new Product(b);  
  19.          Consumer c = new Consumer(b);  
  20.          Consumer c1 = new Consumer(b);  
  21.          new Thread(p).start();  
  22.          new Thread(c).start();  
  23.          new Thread(c1).start();  
  24.      }  
  25.  }  
  26.  //馒头  
  27.  class ManTou{  
  28.      int id;  
  29.      public ManTou(int id) {  
  30.          this.id = id;  
  31.      }  
  32.      @Override  
  33.      public String toString() {  
  34.          return "ManTou"+id;  
  35.      }  
  36.  }  
  37.    
  38.  //装馒头的篮子  
  39.  class Basket{  
  40.      int max = 6;  
  41.      LinkedList<ManTou> manTous = new LinkedList<ManTou>();  
  42.      Lock lock = new ReentrantLock(); //锁对象  
  43.      Condition full = lock.newCondition();  //用来监控篮子是否满的Condition实例  
  44.      Condition empty = lock.newCondition(); //用来监控篮子是否空的Condition实例  
  45.      //往篮子里面放馒头  
  46.      public void push(ManTou m){  
  47.          lock.lock();  
  48.          try {  
  49.              while(max == manTous.size()){  
  50.                  System.out.println("篮子是满的,待会儿再生产...");  
  51.                  full.await();  
  52.              }  
  53.              manTous.add(m);  
  54.              empty.signal();  
  55.          } catch (InterruptedException e) {  
  56.              e.printStackTrace();  
  57.          }finally{  
  58.              lock.unlock();  
  59.          }  
  60.      }  
  61.      //往篮子里面取馒头  
  62.      public ManTou pop(){  
  63.          ManTou m = null;  
  64.          lock.lock();  
  65.          try {  
  66.              while(manTous.size() == 0){  
  67.                  System.out.println("篮子是空的,待会儿再吃...");  
  68.                  empty.await();  
  69.              }  
  70.              m = manTous.removeFirst();  
  71.              full.signal();  
  72.          } catch (InterruptedException e) {  
  73.              e.printStackTrace();  
  74.          }finally{  
  75.              lock.unlock();  
  76.              return m;  
  77.          }  
  78.      }  
  79.  }  
  80.  //生产者  
  81.  class Product implements Runnable{  
  82.      Basket basket;  
  83.      public Product(Basket basket) {  
  84.          this.basket = basket;  
  85.      }  
  86.      public void run() {  
  87.          for (int i = 0; i < 40; i++) {  
  88.              ManTou m = new ManTou(i);  
  89.              basket.push(m);  
  90.              System.out.println("生产了"+m);  
  91.              try {  
  92.                  Thread.sleep((int)(Math.random()*2000));  
  93.              } catch (InterruptedException e) {  
  94.                  e.printStackTrace();  
  95.              }  
  96.                
  97.          }  
  98.      }  
  99.  }  
  100.   
  101. //消费者  
  102. class Consumer implements Runnable{  
  103.     Basket basket;  
  104.     public Consumer(Basket basket) {  
  105.         this.basket = basket;  
  106.     }  
  107.     public void run() {  
  108.         for (int i = 0; i < 20; i++) {  
  109.             try {  
  110.                 Thread.sleep((int)(Math.random()*2000));  
  111.             } catch (InterruptedException e) {  
  112.                 e.printStackTrace();  
  113.             }  
  114.             ManTou m = basket.pop();  
  115.             System.out.println("消费了"+m);  
  116.         }  
  117.     }  
  118. }  
posted @ 2016-12-08 17:28  天涯海角路  阅读(118)  评论(0)    收藏  举报