生產者和消費者是一個多線程同步的經典案例,該問題描述了兩個共享固定大小緩衝區的線程,即所謂的「生產者」和「消費者」,顧名思義,生產者指的就是生產必定的數據量到緩衝區,而消費者就是從緩衝區取走必定的數據。java
生產者和消費者問題要解決一個死鎖問題,就是當緩衝區已經滿的時候,生產者佔着它等待消費者來取走數據,而消費者則等着生產者讓出緩衝區的權利好取走數據,因而就相互等待,從而形成死鎖。多線程
本程序只有一個生產者和一個消費者,使用wait和notify(nitify)方法來避免死鎖問題,這裏得提一下wait和notify(notifyAll)方法,線程中的wait、notify以及notifyAll方法:都是定義在Object類中的final方法,即全部的類都默認擁有這3個方法,但只用於synchronized關鍵字做用的範圍內,而且是搭配着一塊兒使用;wait方法是通知當前線程等待並釋放對象鎖;notify方法是通知等待此對象鎖的一個線程從新得到線程鎖;notifyAll是喚醒全部等待此對象鎖的線程。this
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(); } } } }