在《java 同步和互斥程式說明》這篇文章的基礎上,來實現下面的程式
桌上有一個空盤子,只允許放一個水果。爸爸可以向盤中放蘋果,也可以向盤中放桔子,兒子專等吃盤中的桔子,女兒專等吃盤中的蘋果。規定當盤空時,一次只能放一隻水果。
下面是程式的具體實現代碼,在寫這個程式的時候,有點小問題,糾結了很長時間,於是在csdn論壇上發表文章終於得到瞭解決
先說說涉及到的類的作用,首先Fruits作為一個水果的父類,Apple和Orange是Fruits類的擴充類。CriticalResources類是臨界資源類,作為緩衝區用,裡面封裝了數組大小為一的Fruits數組,可以看成“盤子”;ProducerOrange為生產橘子的類 ProducerApple為生產桔子的類 ConsumerApple(消費蘋果的類) ConsumerOrange(消費桔子的類)
水果類代碼如下
public class Fruits {private String name;public Fruits(String name) {this.name = name;}@Overridepublic String toString() {return name;}public Fruits() {super();}}public class Apple extends Fruits {public Apple(String name) {super(name);}public Apple() {// TODO Auto-generated constructor stub}}public class Orange extends Fruits {public Orange(String name) {super(name);}public Orange() {// TODO Auto-generated constructor stub}}下面是作為緩衝區盤子的代碼
public class CriticalResources {private int index = 0;private static Fruits[] fruites = new Fruits[1];// 預設臨界區有五個商品private ProducerApple pa = new ProducerApple(this);private ProducerOrange po = new ProducerOrange(this);private ConsumerApple ca = new ConsumerApple(this);private ConsumerOrange co = new ConsumerOrange(this);/** * 向臨界資源裡添加商品 利用synchronized關鍵字實現同步 添加後數組指標+1 * 如果臨界資源數組裡面裝滿了商品不能再生產,則生產線程等待以便讓消費者消費 * * @param goods */public synchronized void push(Fruits goods) {//while (this.index == this.fruites.length) {try {this.wait();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}this.notifyAll();// 喚醒生產者this.fruites[index++] = goods;}/** * 從臨界資源裡拿商品,先減一後返回 如果index==0說明, 臨界資源數組裡面沒有商品,不能在消費 消費線程阻塞, 讓生產者生產 則讓生產者 * * @return */public synchronized Fruits pop() {while (this.index == 0) {try {this.wait();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}this.notifyAll();// 喚醒消費者return fruites[--index];}/** * 看看是不是空了 * * @return */public synchronized Fruits peek() {if (this.index == 0)return null;elsereturn fruites[index - 1];}public int getIndex() {return index;}public void setIndex(int index) {this.index = index;}public Fruits[] getFruites() {return fruites;}}下面是生產桔子和消費桔子的代碼
public class ProducerOrange implements Runnable {CriticalResources cr = null;public ProducerOrange(CriticalResources cr) {super();this.cr = cr;}int count = 5; //做5次@Overridepublic void run() { while(count-->0) synchronized (cr) { while (cr.peek() != null) { try { cr.wait();// 該生產這等待 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } Fruits fruits = new Orange("橘子"); cr.push(fruits); System.out.println("橘子生產商生產了" + fruits); cr.notifyAll(); }}}/** * 消費橘子的消費者 * * @author Administrator * */public class ConsumerOrange implements Runnable {private CriticalResources cr = null;// 封裝一個臨界資來源物件,以便消費public ConsumerOrange(CriticalResources cr) {super();this.cr = cr;}int count = 5;@Overridepublic void run() {while (count-- > 0)// 如果緩衝區是蘋果synchronized (cr) {while (!(cr.peek() instanceof Orange)) {try {cr.wait();// 該消費者等待} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}Fruits fruits = cr.pop();System.out.println("----橘子消費者消費了-------" + fruits);cr.notifyAll();}}}下面是生產蘋果核消費蘋果的代碼
/package arthur.thread.producerandcoustomer;/** * 生產蘋果的生產者 * * @author Arthur * */public class ProducerApple implements Runnable {private CriticalResources cr = null;// 封裝一個臨界資來源物件,以便生產public ProducerApple(CriticalResources cr) {super();this.cr = cr;}private int count = 5;@Overridepublic void run() {while (count-- > 0)synchronized (cr) {while ((cr.peek() != null)) {try {cr.wait();// 緩衝區滿,該生產者等待} catch (InterruptedException e) {e.printStackTrace();}}/如果不加鎖,此處容易被打斷Fruits fruits = new Apple("蘋果");cr.push(fruits);System.out.println("蘋果生產商生產了" + fruits);cr.notifyAll();}}}/** * 消費蘋果的消費者 * * @author Arthur * */public class ConsumerApple implements Runnable {private CriticalResources cr = null;// 封裝一個臨界資來源物件,以便消費public ConsumerApple(CriticalResources cr) {super();this.cr = cr;}int count = 5;@Overridepublic void run() { while(count-->0) synchronized (cr) { while (!(cr.peek() instanceof Apple) ) { try { cr.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } Fruits fruits = cr.pop(); System.out.println("----蘋果消費者消費了-------" + fruits); cr.notifyAll(); }}}用戶端代碼
public class Client { /** * @param args */ public static void main(String[] args) { CriticalResources cr = new CriticalResources(); // 生產蘋果執行個體 ProducerApple appleP = new ProducerApple(cr); // 消費蘋果執行個體 ConsumerApple appleC = new ConsumerApple(cr); // 橘子生產者執行個體 ProducerOrange orangeP = new ProducerOrange(cr); // 橘子消費者執行個體 ConsumerOrange orangeC = new ConsumerOrange(cr); // 生產蘋果線程 Thread pThread = new Thread(appleP); // 消費蘋果線程 Thread cThread = new Thread(appleC); // 生產橘子線程 Thread pt = new Thread(orangeP); // 消費橘子線程 Thread ct = new Thread(orangeC); pThread.start(); cThread.start(); pt.start(); ct.start(); }}運行結果
蘋果生產商生產了蘋果
----蘋果消費者消費了-------蘋果
橘子生產商生產了橘子
----橘子消費者消費了-------橘子
蘋果生產商生產了蘋果
----蘋果消費者消費了-------蘋果
橘子生產商生產了橘子
----橘子消費者消費了-------橘子
蘋果生產商生產了蘋果
----蘋果消費者消費了-------蘋果
橘子生產商生產了橘子
----橘子消費者消費了-------橘子
蘋果生產商生產了蘋果
----蘋果消費者消費了-------蘋果
橘子生產商生產了橘子
----橘子消費者消費了-------橘子
蘋果生產商生產了蘋果
----蘋果消費者消費了-------蘋果
橘子生產商生產了橘子
----橘子消費者消費了-------橘子