使用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. lock不再用synchronize把同步代码包装起来;
- 2. 阻塞需要另外一个对象condition;
- 3. 同步和唤醒的对象是condition而不是lock,对应的方法是await和signal,而不是wait和notify。
为什么需要使用condition呢?简单一句话,lock更灵活。以前的方式只能有一个等待队列,在实际应用时可能需要多个,比如读和写。为了这个灵活性,lock将同步互斥控制和等待队列分离开来,互斥保证在某个时刻只有一个线程访问临界区(lock自己完成),等待队列负责保存被阻塞的线程(condition完成)。
通过查看ReentrantLock的源代码发现,condition其实是等待队列的一个管理者,condition确保阻塞的对象按顺序被唤醒。
在Lock的实现中,LockSupport被用来实现线程状态的改变,后续将更进一步研究LockSupport的实现机制。
- 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);
- }
- }
- }

浙公网安备 33010602011771号