生产者和消费者是一个多线程同步的经典案例,该问题描述了两个共享固定大小缓冲区的线程,即所谓的“生产者”和“消费者”,顾名思义,生产者指的就是生产一定的数据量到缓冲区,而消费者就是从缓冲区取走一定的数据。
生产者和消费者问题要解决一个死锁问题,就是当缓冲区已经满的时候,生产者占着它等待消费者来取走数据,而消费者则等着生产者让出缓冲区的权利好取走数据,于是就相互等待,从而造成死锁。
本程序只有一个生产者和一个消费者,使用wait和notify(nitify)方法来避免死锁问题,这里得提一下wait和notify(notifyAll)方法,线程中的wait、notify以及notifyAll方法:都是定义在Object类中的final方法,即所有的类都默认拥有这3个方法,但只用于synchronized关键字作用的范围内,并且是搭配着一起使用;wait方法是通知当前线程等待并释放对象锁;notify方法是通知等待此对象锁的一个线程重新获得线程锁;notifyAll是唤醒所有等待此对象锁的线程。
public class ProducerConsumer { public static void main(String[] args) { SyncStack myStack = new SyncStack(6); Producer producer = new Producer(myStack); Consumer consumer = new Consumer(myStack); Thread t1 = new Thread(producer); Thread t2 = new Thread(consumer); t1.start(); t2.start(); }}class Bread { private int id; Bread(int id) { this.id = id; } public int getId() { return id; }}class SyncStack { private int size; private int index = 0; private Bread[] myBread; SyncStack(int size) { this.size = size; myBread = new Bread[size]; } public synchronized void put(Bread bread) { while (index == size) { try { this.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } myBread[index] = bread; ++index; System.out.println("Producer puts bread: " + bread.getId()); this.notify(); } public synchronized Bread remove() { while (index == 0) { try { this.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } --index; System.out.println("Consumer removers bread: " + myBread[index].getId()); this.notify(); return myBread[index]; } }class Producer extends Thread { private SyncStack myStack; Producer(SyncStack myStack) { this.myStack = myStack; } public void run() { for (int i = 1; i <= 20; ++i) { myStack.put(new Bread(i)); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }}class Consumer extends Thread { private SyncStack myStack; Consumer(SyncStack myStack) { this.myStack = myStack; } public void run() { for (int i = 1; i <= 20; ++i) { Bread bread = myStack.remove(); try { Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }}