Java实现生产者消费者模式

本文介绍了生产者消费者模式的四种实现方式,包括使用Object的wait和notifyAll、使用Condition的await和signal、使用Vector和BlockingQueue等。每种实现方式都详细展示了代码示例,并分析了各自的优缺点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

介绍生产者消费者模式的四种不同实现


实现1:Object,wait,notifyAll

说明:生成String对象作为锁,通过boolean型变量hasValue来判断队列是否为空

(缺点:队列中仅包含一个对象)

注意:用notifyAll不用notify防止唤醒同类进程而锁住。

// 通过Object对象的wait,notifyAll实现
public class PC {
  private String lock ="i am a lock";
  private boolean hasValue = false;

  public void setValue() {
    try {
      synchronized (lock) {
        while (hasValue) {
          System.out.println(Thread.currentThread().getName() + " waiting...");
          lock.wait();
        }
        System.out.println(Thread.currentThread().getName() + " runnable...");
        hasValue = true;
        lock.notifyAll();
      }
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }

  public void getValue() {
    try {
      synchronized (lock) {
        while (!hasValue) {
          System.out.println(Thread.currentThread().getName() + " waiting...");
          lock.wait();
        }
        System.out.println(Thread.currentThread().getName() + " runnable...");
        hasValue = false;
        lock.notifyAll();
      }
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }

  public static void main(String[] args) {
    PC pc = new PC();
    P[] ps = new P[5];
    C[] cs = new C[5];
    for (int i = 0; i < 5; i++) {
      ps[i] = new P(pc);
      ps[i].setName("生产者" + (i + 1));
      cs[i] = new C(pc);
      cs[i].setName("消费者" + (i + 1));
      ps[i].start();
      cs[i].start();
    }
  }
}

class P extends Thread {
  private PC pc;

  public P(PC pc) {
    super();
    this.pc = pc;
  }

  @Override
  public void run() {
    while (true) {
      pc.setValue();
    }
  }
}

class C extends Thread {
  private PC pc;

  public C(PC pc) {
    super();
    this.pc = pc;
  }

  @Override
  public void run() {
    while (true) {
      pc.getValue();
    }
  }
}

输出: 

生产者1 runnable...
生产者1 waiting...
消费者2 runnable...
消费者2 waiting...
消费者1 waiting...
生产者1 runnable...
生产者1 waiting...
消费者2 runnable...
消费者2 waiting...
消费者1 waiting...
生产者3 runnable...
生产者3 waiting...
生产者1 waiting...
消费者3 runnable...
消费者3 waiting...
消费者4 waiting...
生产者2 runnable...
生产者2 waiting...
生产者5 waiting...
消费者1 runnable...
消费者1 waiting...
生产者3 runnable...
生产者3 waiting...
生产者1 waiting...
消费者5 runnable...
消费者5 waiting...
生产者4 runnable...
生产者4 waiting...

...


实现2:Condition,await,signal

说明:生成ReentrantLcok对象作为锁,通过Condition对象控制等待与唤醒,boolean型hasValue判断队列是否为空(缺点:队列中仅包含一个对象)

注意:finally中unlock锁

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

// 通过Condition对象的await,signal实现
public class PC {
  private ReentrantLock lock = new ReentrantLock();
  private Condition condition = lock.newCondition();
  private boolean hasValue = false;

  public void set() {
    try {
      lock.lock();
      while (hasValue == true) {
        System.out.println(Thread.currentThread().getName() + " waiting...");
        condition.await();
      }
      System.out.println(Thread.currentThread().getName() + " runnable...");
      hasValue = true;
      condition.signal();
    } catch (InterruptedException e) {
      e.printStackTrace();
    } finally {
      lock.unlock();
    }
  }

  public void get() {
    try {
      lock.lock();
      while (hasValue == false) {
        System.out.println(Thread.currentThread().getName() + " waiting...");
        condition.await();
      }
      System.out.println(Thread.currentThread().getName() + " runnable...");
      hasValue = false;
      condition.signal();
    } catch (InterruptedException e) {
      e.printStackTrace();
    } finally {
      lock.unlock();
    }
  }
  
  public static void main(String[] args) {
    PC pc = new PC();
    P[] ps = new P[5];
    C[] cs = new C[5];
    for(int i =0;i<5;i++){
      ps[i] = new P(pc);
      ps[i].setName("生产者"+(i+1));
      cs[i] = new C(pc);
      cs[i].setName("消费者"+(i+1));
      ps[i].start();
      cs[i].start();
    }
  }

}

class P extends Thread {
  private PC pc;

  public P(PC pc) {
    this.pc = pc;
  }
  @Override
  public void run() {
    pc.set();
  }
}

class C extends Thread {
  private PC pc;

  public C(PC pc) {
    this.pc = pc;
  }

  @Override
  public void run() {
    pc.get();
  }
}

输出:

生产者1 runnable...
生产者2 waiting...
消费者1 runnable...
消费者2 waiting...
生产者3 runnable...
消费者3 runnable...
生产者4 runnable...
消费者4 runnable...
生产者5 runnable...
消费者5 runnable...
生产者2 runnable...
消费者2 runnable...


实现3:Queue,wait,signalAll

说明:生成Vector对象作为锁,通过队列size判断队列长度,实现队列中存储多个对象。

import java.util.Vector;
// 通过Object的wait,notifyAll实现
public class PC {
  public static void main(String[] args) {
    Vector<Integer> shareQueue = new Vector<>();
    int size = 2;
    Thread p = new Thread(new P(shareQueue, size));
    Thread c = new Thread(new C(shareQueue));
    p.start();
    c.start();
  }
}

class P extends Thread {

  private final Vector<Integer> shareQueue;
  private final int size;

  public P(Vector<Integer> shareQueue, int size) {
    this.shareQueue = shareQueue;
    this.size = size;
  }

  @Override
  public void run() {
    for (int i = 0; i < 5; i++) {
      try {
        produce(i);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
    try {
      // -1 as sentinel 
      produce(-1);
      System.out.println("finish producing ...");
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }

  public void produce(int i) throws InterruptedException {
    while (shareQueue.size() == size) {
      synchronized (shareQueue) {
        System.out.println("queue is full ... " + "waiting to produce " + i);
        shareQueue.wait();
      }
    }
    System.out.println("produce ... " + i);
    synchronized (shareQueue) {
      shareQueue.add(i);
      shareQueue.notifyAll();
    }
  }
}

class C extends Thread {

  private final Vector<Integer> shareQueue;

  public C(Vector<Integer> shareQueue) {
    this.shareQueue = shareQueue;
  }

  @Override
  public void run() {
    while (true) {
      try {
        while (shareQueue.isEmpty()) {
          synchronized (shareQueue) {
            System.out.println("queue is empty ...");
            shareQueue.wait();
          }
        }
        synchronized (shareQueue) {
          shareQueue.notifyAll();
          int i = shareQueue.remove(0);
          if (i == -1) {
            System.out.println("finish consuming ...");
            return;
          }
          System.out.println("consume ... " + i);
        }
        Thread.sleep(20);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }

}

 输出:

queue is empty ...
produce ... 0
produce ... 1
consume ... 0
produce ... 2
queue is full ... waiting to produce 3
consume ... 1
produce ... 3
queue is full ... waiting to produce 4
consume ... 2
produce ... 4
queue is full ... waiting to produce -1
consume ... 3
produce ... -1
finish producing ...
consume ... 4
finish consuming ...


实现4:BlockingQueue,put,take

说明:java.util.concurrent.BlockingQueue封装了ReentrantLock,操作简单

注意:输出不同步会有一些错误,但内部实现是没有问题的,可参考ArrayBlockingQueue源码put,take的实现。

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
// 通过BlockingQueue的put,take实现
public class PC {

  private static final int capacity = 2;

  private static BlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(capacity);

  static class P extends Thread {

    @Override
    public void run() {
      for (int i = 0; i < 10; i++) {
        try {
          queue.put(i);
          System.out.println("produce ... " + i);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    }
  }

  static class C extends Thread {
    @Override
    public void run() {
      while (true) {
        try {
          while (!queue.isEmpty()) {
            int take = queue.take();
            System.out.println("consume... " + take);
          }
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    }
  }

  public static void main(String[] args) {
    try {
      P p = new P();
      p.start();
      Thread.sleep(10);
      C c = new C();
      c.start();
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}

输出:

produce ... 0
produce ... 1
consume... 0
consume... 1
consume... 2
produce ... 2
produce ... 3
produce ... 4
produce ... 5
consume... 3
consume... 4
produce ... 6
consume... 5
consume... 6
consume... 7
produce ... 7
produce ... 8
produce ... 9
consume... 8
consume... 9

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值