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

本文探讨了在解决生产者消费者问题时,如何从传统的wait/notify方法转向使用Lock。Lock提供了更灵活的控制,不再需要synchronized包裹代码,并引入了Condition对象来管理阻塞线程。Condition使得可以创建多个等待队列,适应更复杂的同步需求。此外,文章还提及LockSupport在改变线程状态中的作用,为后续深入研究打下基础。
摘要由CSDN通过智能技术生成

在使用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. lock不再用synchronize把同步代码包装起来;
  • 2. 阻塞需要另外一个对象condition;
  • 3. 同步和唤醒的对象是condition而不是lock,对应的方法是awaitsignal,而不是wait和notify。

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

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

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

 

[Java] 纯文本查看 复制代码
?
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
<font style="color:rgb(77, 77, 77)"><font face="&quot"><font style="font-size:16px"package com.thread;
   
  import java.util.LinkedList;
  import java.util.concurrent.locks.Condition;
  import java.util.concurrent.locks.Lock;
  import java.util.concurrent.locks.ReentrantLock;
   
   
  /**
   * 使用Lock来实现生产者和消费者问题
   *
   *
   *
   */
  public class ProducerConsumer {
      public static void main(String[] args) {
          Basket b = new Basket();
          Product p = new Product(b);
          Consumer c = new Consumer(b);
          Consumer c1 = new Consumer(b);
          new Thread(p).start();
          new Thread(c).start();
          new Thread(c1).start();
      }
  }
  //馒头
  class ManTou{
      int id;
      public ManTou(int id) {
          this.id = id;
      }
      @Override
      public String toString() {
          return "ManTou"+id;
      }
  }
   
  //装馒头的篮子
  class Basket{
      int max = 6;
      LinkedList<ManTou> manTous = new LinkedList<ManTou>();
      Lock lock = new ReentrantLock(); //锁对象
      Condition full = lock.newCondition();  //用来监控篮子是否满的Condition实例
      Condition empty = lock.newCondition(); //用来监控篮子是否空的Condition实例
      //往篮子里面放馒头
      public void push(ManTou m){
          lock.lock();
          try {
              while(max == manTous.size()){
                  System.out.println("篮子是满的,待会儿再生产...");
                  full.await();
              }
              manTous.add(m);
              empty.signal();
          } catch (InterruptedException e) {
              e.printStackTrace();
          }finally{
              lock.unlock();
          }
      }
      //往篮子里面取馒头
      public ManTou pop(){
          ManTou m = null;
          lock.lock();
          try {
              while(manTous.size() == 0){
                  System.out.println("篮子是空的,待会儿再吃...");
                  empty.await();
              }
              m = manTous.removeFirst();
              full.signal();
          } catch (InterruptedException e) {
              e.printStackTrace();
          }finally{
              lock.unlock();
              return m;
          }
      }
  }
  //生产者
  class Product implements Runnable{
      Basket basket;
      public Product(Basket basket) {
          this.basket = basket;
      }
      public void run() {
          for (int i = 0; i < 40; i++) {
              ManTou m = new ManTou(i);
              basket.push(m);
              System.out.println("生产了"+m);
              try {
                  Thread.sleep((int)(Math.random()*2000));
              } catch (InterruptedException e) {
                  e.printStackTrace(); 在使用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. lock不再用synchronize把同步代码包装起来;
  • 2. 阻塞需要另外一个对象condition;
  • 3. 同步和唤醒的对象是condition而不是lock,对应的方法是awaitsignal,而不是wait和notify。

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

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

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

 

[Java] 纯文本查看 复制代码
?
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
<font style="color:rgb(77, 77, 77)"><font face="&quot"><font style="font-size:16px"package com.thread;
   
  import java.util.LinkedList;
  import java.util.concurrent.locks.Condition;
  import java.util.concurrent.locks.Lock;
  import java.util.concurrent.locks.ReentrantLock;
   
   
  /**
   * 使用Lock来实现生产者和消费者问题
   *
   *
   *
   */
  public class ProducerConsumer {
      public static void main(String[] args) {
          Basket b = new Basket();
          Product p = new Product(b);
          Consumer c = new Consumer(b);
          Consumer c1 = new Consumer(b);
          new Thread(p).start();
          new Thread(c).start();
          new Thread(c1).start();
      }
  }
  //馒头
  class ManTou{
      int id;
      public ManTou(int id) {
          this.id = id;
      }
      @Override
      public String toString() {
          return "ManTou"+id;
      }
  }
   
  //装馒头的篮子
  class Basket{
      int max = 6;
      LinkedList<ManTou> manTous = new LinkedList<ManTou>();
      Lock lock = new ReentrantLock(); //锁对象
      Condition full = lock.newCondition();  //用来监控篮子是否满的Condition实例
      Condition empty = lock.newCondition(); //用来监控篮子是否空的Condition实例
      //往篮子里面放馒头
      public void push(ManTou m){
          lock.lock();
          try {
              while(max == manTous.size()){
                  System.out.println("篮子是满的,待会儿再生产...");
                  full.await();
              }
              manTous.add(m);
              empty.signal();
          } catch (InterruptedException e) {
              e.printStackTrace();
          }finally{
              lock.unlock();
          }
      }
      //往篮子里面取馒头
      public ManTou pop(){
          ManTou m = null;
          lock.lock();
          try {
              while(manTous.size() == 0){
                  System.out.println("篮子是空的,待会儿再吃...");
                  empty.await();
              }
              m = manTous.removeFirst();
              full.signal();
          } catch (InterruptedException e) {
              e.printStackTrace();
          }finally{
              lock.unlock();
              return m;
          }
      }
  }
  //生产者
  class Product implements Runnable{
      Basket basket;
      public Product(Basket basket) {
          this.basket = basket;
      }
      public void run() {
          for (int i = 0; i < 40; i++) {
              ManTou m = new ManTou(i);
              basket.push(m);
              System.out.println("生产了"+m);
              try {
                  Thread.sleep((int)(Math.random()*2000));
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
               
          }
      }
  }
  
 //消费者
 class Consumer implements Runnable{
     Basket basket;
     public Consumer(Basket basket) {
         this.basket = basket;
     }
     public void run() {
         for (int i = 0; i < 20; i++) {
             try {
                 Thread.sleep((int)(Math.random()*2000));
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
             ManTou m = basket.pop();
             System.out.println("消费了"+m);
         }
     }
</font></font></font>
              }
               
          }
      }
  }
  
 //消费者
 class Consumer implements Runnable{
     Basket basket;
     public Consumer(Basket basket) {
         this.basket = basket;
     }
     public void run() {
         for (int i = 0; i < 20; i++) {
             try {
                 Thread.sleep((int)(Math.random()*2000));
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
             ManTou m = basket.pop();
             System.out.println("消费了"+m);
         }
     }
</font></font></font>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值