多线程生产者消费者案例

题目需求:写一个生产者消费者容器,支持多个生产者消费者同时访问,容器里最多放十个数,需要get()和put()方法,当容器中没数据时,生产者开始生产数据,消费者等待,数据量满十个时,生产者等待,消费者开始消费.

/**
 * Created by canner on 2018/11/30.
 */
public class MyContainer<T> {

    private final int MAX = 10;

    private final LinkedList<T> list = new LinkedList<>();

    private int count = 0;

   private Lock lock = new ReentrantLock();
   private Condition producer = lock.newCondition();
   private Condition consumer = lock.newCondition();

   public void put(T t){
       try {
// 拿到当前对象的锁,锁定对象 lock.lock();
while(list.size() == MAX){ try { producer.await(); } catch (InterruptedException e) { e.printStackTrace(); } } list.add(t); ++ count;       // 唤醒所有消费者 consumer.signalAll(); } finally {
       // 释放锁 lock.unlock(); } }
public T get(){ try {
       // 拿到当前对象的锁 lock.lock();
// 当容器数量为0时,消费者等待
while (list.size() == 0){ try { consumer.await(); } catch (InterruptedException e) { e.printStackTrace(); } } T t = list.removeFirst(); count -- ;
      // 唤醒所有生产者 producer.signalAll();
return t; } finally { lock.unlock(); } } public static void main(String[] args) { final MyContainer<String> contaional = new MyContainer<>(); for (int i = 0; i < 2; i++) { new Thread(new Runnable() { @Override public void run() { while (true){ contaional.put("线程:"+Thread.currentThread().getName()+" 生产数据"); System.out.println(String.format("往容器放数据-->线程名[%s]",Thread.currentThread().getName())); } } }, "p" + i).start(); } for (int i = 0; i < 5; i++) { new Thread(new Runnable() { @Override public void run() { while (true){ System.out.println("消费" + contaional.get()); } } }, "c"+i).start(); } } }

本题的坑:①:一定要选同while,因为当容器满了的时候,会唤醒消费者消费,消费者消费了一个会signalAll()所有生产者,所以存在当生产者A拿到锁生产之后,生产者B接着拿到了这把锁,由于没有用while做二次判断,所以接着往下执行,容器的最大数量就超过10了.
     ②:一定要用sinalAll()而不是sinal(),必须唤醒所有的线程,只唤醒一个线程的时候程序有可能造成所有线程都在await()状态.
本题选用sychronized使用wait()和notifyAll()是相同的做法,只是用Lock加Conditon的优势在于能选定唤醒哪种类型的线程.
原文地址:https://www.cnblogs.com/icanner/p/10043977.html