生产者消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者取走数据。
1. 使用阻塞队列实现生产者消费者模式
生产者:
1 public class Producer implements Runable{ 2 private final BlockingQueue sharedQueue; 3 public Producer(BlockingQueue sharedQueue){ 4 this.sharedQueue = sharedQueue; 5 } 6 7 publlic void run(){ 8 for(i=0;i<10;i++){ 9 try{ 10 System.out.println("Producer:"+i); 11 sharedQueue.put(i); 12 }catch(InterruptedException ex){ 13 System.out.println("exception:"+ex); 14 } 15 } 16 } 17 }
消费者:
public class Consumer implements Runable{ private final BlockingQueue sharedQueue; public Consumer(BlockingQueue sharedQueue){ this.sharedQueue = sharedQueue } public void run(){ while(true){ try{ System.out.println("Consumed:"+sharedQueue.take()); }catch(InterruptedException ex){ System.out.println("Exception:"+ex); } } } }
生产者消费者模式:
public class ProducerConsumerPattern { private static final Logger logger = public static void main(String[] args) { //阻塞队列 BlockingQueue sharedQueue = new LinkedBlockingDeque(); //创建生产者和消费者,共享队列 Thread prodThread = new Thread(new Producer(sharedQueue)); Thread consThread = new Thread(new Consumer(sharedQueue)); //开启生产者和消费者进程 prodThread.start(); consThread.start(); } }
BlockingQueue是一个阻塞队列,它的存取可以保证只有一个线程在进行,所以根据逻辑,生产者在内存满的时候进行等待,并且唤醒消费者队列,反过来消费者在饥饿状态下等待并唤醒生产者进行生产。
2. wait/notify方法实现
/** * 生产者消费者模式:使用Object.wait() / notify()方法实现 */ public class ProducerConsumer { private static final int CAPACITY = 5; public static void main(String args[]){ Queue<Integer> queue = new LinkedList<Integer>(); Thread producer1 = new Producer("P-1", queue, CAPACITY); Thread producer2 = new Producer("P-2", queue, CAPACITY); Thread consumer1 = new Consumer("C1", queue, CAPACITY); Thread consumer2 = new Consumer("C2", queue, CAPACITY); Thread consumer3 = new Consumer("C3", queue, CAPACITY); producer1.start(); producer2.start(); consumer1.start(); consumer2.start(); consumer3.start(); } /** * 生产者 */ public static class Producer extends Thread{ private Queue<Integer> queue; String name; int maxSize; int i = 0; public Producer(String name, Queue<Integer> queue, int maxSize){ super(name); this.name = name; this.queue = queue; this.maxSize = maxSize; } @Override public void run(){ while(true){ synchronized(queue){ while(queue.size() == maxSize){ try { System.out .println("Queue is full, Producer[" + name + "] thread waiting for " + "consumer to take something from queue."); queue.wait(); } catch (Exception ex) { ex.printStackTrace(); } } System.out.println("[" + name + "] Producing value : +" + i); queue.offer(i++); queue.notifyAll(); try {
Thread.sleep(new Random().nextInt(1000));//模拟随机生产 } catch (InterruptedException e) { e.printStackTrace(); } } } } } /** * 消费者 */ public static class Consumer extends Thread{ private Queue<Integer> queue; String name; int maxSize; public Consumer(String name, Queue<Integer> queue, int maxSize){ super(name); this.name = name; this.queue = queue; this.maxSize = maxSize; } @Override public void run(){ while(true){ synchronized(queue){ while(queue.isEmpty()){ try { System.out.println("Queue is empty, Consumer[" + name + "] thread is waiting for Producer"); queue.wait(); } catch (Exception ex) { ex.printStackTrace(); } } int x = queue.poll(); System.out.println("[" + name + "] Consuming value : " + x); queue.notifyAll(); try { Thread.sleep(new Random().nextInt(1000));//模拟随机消费 } catch (InterruptedException e) { e.printStackTrace(); } } } } } }
wait()
:当缓冲区已满/空时,生产者/消费者线程停止自己的执行,放弃锁,使自己处于等待状态,让其他线程执行。notify()
:当生产者/消费者向缓冲区放入/取出一个产品时,向其他等待的线程发出可执行的通知,同时放弃锁,使自己处于等待状态。
3. 使用Lock和Condition的await() / signal()方法
/** * 生产者消费者模式:使用Lock和Condition实现 * {@link java.util.concurrent.locks.Lock} * {@link java.util.concurrent.locks.Condition} */ public class ProducerConsumerByLock { private static final int CAPACITY = 5; private static final Lock lock = new ReentrantLock(); private static final Condition fullCondition = lock.newCondition(); //队列满的条件 private static final Condition emptyCondition = lock.newCondition(); //队列空的条件 public static void main(String args[]){ Queue<Integer> queue = new LinkedList<Integer>(); Thread producer1 = new Producer("P-1", queue, CAPACITY); Thread producer2 = new Producer("P-2", queue, CAPACITY); Thread consumer1 = new Consumer("C1", queue, CAPACITY); Thread consumer2 = new Consumer("C2", queue, CAPACITY); Thread consumer3 = new Consumer("C3", queue, CAPACITY); producer1.start(); producer2.start(); consumer1.start(); consumer2.start(); consumer3.start(); } /** * 生产者 */ public static class Producer extends Thread{ private Queue<Integer> queue; String name; int maxSize; int i = 0; public Producer(String name, Queue<Integer> queue, int maxSize){ super(name); this.name = name; this.queue = queue; this.maxSize = maxSize; } @Override public void run(){ while(true){ //获得锁 lock.lock(); while(queue.size() == maxSize){ try { System.out .println("Queue is full, Producer[" + name + "] thread waiting for " + "consumer to take something from queue."); //条件不满足,生产阻塞 fullCondition.await(); } catch (InterruptedException ex) { ex.printStackTrace(); } } System.out.println("[" + name + "] Producing value : +" + i); queue.offer(i++); //唤醒其他所有生产者、消费者 fullCondition.signalAll(); emptyCondition.signalAll(); //释放锁 lock.unlock(); try { Thread.sleep(new Random().nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } } } } /** * 消费者 */ public static class Consumer extends Thread{ private Queue<Integer> queue; String name; int maxSize; public Consumer(String name, Queue<Integer> queue, int maxSize){ super(name); this.name = name; this.queue = queue; this.maxSize = maxSize; } @Override public void run(){ while(true){ //获得锁 lock.lock(); while(queue.isEmpty()){ try { System.out.println("Queue is empty, Consumer[" + name + "] thread is waiting for Producer"); //条件不满足,消费阻塞 emptyCondition.await(); } catch (Exception ex) { ex.printStackTrace(); } } int x = queue.poll(); System.out.println("[" + name + "] Consuming value : " + x); //唤醒其他所有生产者、消费者 fullCondition.signalAll(); emptyCondition.signalAll(); //释放锁 lock.unlock(); try { Thread.sleep(new Random().nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } } } } }
4. 总结
实现生产者消费者模式有3点:
1. 拿什么作为缓冲区,给生产者和消费者解耦,平衡了生产者和消费者的处理能力。一般使用队列
2. 构建生产者,队列满使得生产者线程阻塞
3. 构建消费者 ,队列空使得消费者现成阻塞
参考:https://blog.csdn.net/u010983881/article/details/78554671