13.4.3 多生产者的模拟程序设计及分析

【实例13.17】本节的实例将让条件变得更加复杂,设计了两个厨师和两个营业员。针对这种复杂的现象,先来看看程序的流程,如图13.4所示。


为了能够更加清晰地理解这个程序,下面将分步骤实现这个实例程序。

(1)箱子类的设计代码如下所示。


01 ///创建一个汉堡包盒子的类

02 ///totalmaterial1、totalmaterial2是指所有的能做汉堡包的材料

03 ///box1、box2是一个监视器对象

04 ///sales1、sales2是指销售了多少个汉堡包

05 ///production1、production2是指总共有多少个汉堡包

06 class ham

07 {

08 static Object box1=new Object();

09 static Object box2=new Object();

10 static int totalmaterial1=10;

11 static int totalmaterial2=10;

12 static int sales11=0;

13 static int sales12=0;

14 static int sales21=0;

15 static int sales22=0;

16 static int production1=5;

17 static int production2=5;

18 }


13.4.3 多生产者的模拟程序设计及分析 - 图1

图 13.4 多生产者和多消费者线程模拟程序

(2)第1个厨师类的设计,代码如下:


19 ///这是一个厨师的线程类

20 ///make方法使用了一个同步块,在这个函数里会不断地生产汉堡包。这个厨师生产的是A类汉

21 ///堡包

22 ///run方法就是线程需要运行的内容

23 ///使用循环语句来保证在汉堡包材料用完之前,不断地生产汉堡包

24 ///使用判断语句判断只要有汉堡包,厨师就通知营业员可以卖了

25 class hmaker1 extends Thread

26 {

27 public void make()

28 {

29 synchronized(ham.box1)

30 {

31 (ham.production1)++;

32 System.out.println("厨师"+getName()+":"+"汉堡来了(总共"

33 +(ham.production1-ham.sales11-ham.sales12)+"个A类汉堡)");

34 }

35 try

36 {

37 ham.box1.notify();

38 }

39 catch(Exception e){}

40 }

41 public void run()

42 {

43 while(ham.production1<ham.totalmaterial1)

44 {

45 make();

46 try

47 {

48 sleep(3000);

49 }

50 catch(Exception e){}

51 }

52 if(ham.production1==ham.totalmaterial1)

53 {

54 System.out.println("所有的材料用完了!");

55 }

56 }

57 }


(3)第2个厨师类的设计,其代码如下:


58 ///这是一个厨师的线程类

59 ///make方法使用了一个同步块,在这个函数里会不断地生产汉堡包。这个厨师生产的是B类汉

60 ///堡包

61 ///run方法就是线程需要运行的内容

62 ///使用循环语句来保证在汉堡包材料用完之前,不断地生产汉堡包

63 ///使用判断语句判断只要有汉堡包,厨师就通知营业员可以卖了

64 class hmaker2 extends Thread

65 {

66 public void make()

67 {

68 synchronized(ham.box2)

69 {

70 (ham.production2)++;

71 System.out.println("厨师"+getName()+":"+"汉堡来了(总共

72 "+(ham.production2-ham.sales21-ham.sales22)+"个B类汉堡)");

73 }

74 try

75 {

76 ham.box2.notify();

77 }

catch(Exception e){}

78 }

79 public void run()

80 {

81 while(ham.production2<ham.totalmaterial2)

82 {

83 make();

84 try

85 {

86 sleep(3000);

87 }

88 catch(Exception e){}

89 }

90 if(ham.production2==ham.totalmaterial2)

91 {

92 System.out.println("所有的材料用完了!");

93 }

94 }

95 }


(4)营业员类的设计,其代码如下。


96 ///这是一个营业员的线程类

97 ///sell1、sell2函数都是营业员卖汉堡包的方法

98 ///run方法就是线程需要运行的内容

99 ///使用条件判断语句来判断汉堡包盒子里面是否还有汉堡包

100 ///在run方法内使用循环语句来使得营业员在盒子里有汉堡包的情况下不断地卖

101 class hassistant extends Thread

102 {

103 public void sell1()

104 {

105 if(ham.production1==(ham.sales11+ham.sales12))

106 {

107 System.out.println("营业员"+getName()+":顾客朋友们,请稍微等一下,A型汉堡

108没了!");

109 ham.sales11=0;

110 ham.sales12=0;

111 ham.production1=0;

112 try

113 {

114 ham.box1.wait();

115 }

116 catch(Exception e){}

117 }

118 else

119 {

120 if(ham.production1>(ham.sales11+ham.sales12))

121 {

ham.sales11++;

122 ham.sales21++;

123 System.out.println("营业员"+getName()+":顾客好,汉堡上来了,(总共卖了

124 A类汉堡"+ham.sales11+"个),总共卖了B类汉堡"+ham.sales21+"个)");

125 }

126 }

127 }

128 129

public void sell2()

130 {

131 if(ham.production2==(ham.sales21+ham.sales22))

132 {

133 System.out.println("营业员"+getName()+":顾客朋友们,请稍微等一下,B型汉堡

134 没了!");

135 ham.sales21=0;

136 ham.sales22=0;

137 ham.production2=0;

138 try

139 {

140 ham.box2.wait();

141 }

142 catch(Exception e){}

143 }

144 else

145 {

146 if(ham.production2>(ham.sales21+ham.sales22))

147 {

148 ham.sales12++;

149 ham.sales22++;

150 System.out.println("营业员"+getName()+":顾客好,汉堡上来了,(总共卖了

151 A类汉堡"+ham.sales12+"个,总共卖了B类汉堡"+ham.sales22+"个");

152 }

153 }

154 }

155 public void run()

156 {

157 while((ham.sales12+ham.sales11)<ham.production1)

158 {

159 try

160 {

161 sleep(1000);

162 }

163 catch(Exception e){}

164 sell1();

165 }

166 while((ham.sales12+ham.sales22)<ham.production2)

167 {

168 try

169 {

170 sleep(2000);

171 }

172 catch(Exception e){}

173 sell2();

174 }

175 System.out.println("还剩下A类汉堡:

176 "+(ham.production1-ham.sales11-ham.sales12)+"个");

177 System.out.println("还剩下B类汉堡:

178 "+(ham.production2-ham.sales21-ham.sales22)+"个");

179 }

180 }


(5)线程类在主运行程序中的代码如下。


181 ///这是主运行类

182 ///maker1对象是指厨师对象

183 ///maker2对象是指另一个厨师对象

184 ///assistant1是指第一个营业员对象

185 ///assistant2是指第二个营业员对象

186 ///set方法是通过设置名字不同而区分不同的营业员

187 ///start方法是线程的开始

188 public class thread41

189 {

190 public static void main(String[]args)

191 {

192 hmaker1 maker1=new hmaker1();

193 hmaker2 maker2=new hmaker2();

194 hassistant assistant1=new hassistant();

195 hassistant assistant2=new hassistant();

196 maker1.setName("甲");

197 maker2.setName("乙");

198 assistant1.setName("甲");

199 assistant2.setName("乙");

200 maker1.start();

201 maker2.start();

202 assistant1.start();

203 assistant2.start();

204 }

205 }


【代码说明】从上面代码中可以看出,无论多少个厨师类,或者无论多少个营业员类,都不难,只需将每个类继承或实现成线程类,让它们在特殊的情况下交替执行。

【运行效果】


厨师甲:汉堡来了(总共6个A类汉堡)

厨师乙:汉堡来了(总共6个B类汉堡)

营业员甲:顾客好,汉堡上来了,(总共卖了A类汉堡1个,总共卖了B类汉堡1个)

营业员乙:顾客好,汉堡上来了,(总共卖了A类汉堡2个,总共卖了B类汉堡2个)

营业员甲:顾客好,汉堡上来了,(总共卖了A类汉堡3个,总共卖了B类汉堡3个)

营业员乙:顾客好,汉堡上来了,(总共卖了A类汉堡4个,总共卖了B类汉堡4个)

厨师甲:汉堡来了(总共3个A类汉堡)

厨师乙:汉堡来了(总共3个B类汉堡)

营业员甲:顾客好,汉堡上来了,(总共卖了A类汉堡5个,总共卖了B类汉堡5个)

营业员乙:顾客好,汉堡上来了,(总共卖了A类汉堡6个,总共卖了B类汉堡6个)

营业员甲:顾客好,汉堡上来了,(总共卖了A类汉堡7个,总共卖了B类汉堡7个)

营业员乙:顾客朋友们,请稍微等一下,A型汉堡没了!

厨师甲:汉堡来了(总共1个A类汉堡)

厨师乙:汉堡来了(总共1个B类汉堡)

营业员甲:顾客好,汉堡上来了,(总共卖了A类汉堡1个,总共卖了B类汉堡1个)

营业员乙:顾客朋友们,请稍微等一下,B型汉堡没了!

还剩下A类汉堡:0个

还剩下B类汉堡:0个

营业员甲:顾客朋友们,请稍微等一下,B型汉堡没了!

还剩下A类汉堡:0个

还剩下B类汉堡:0个

厨师甲:汉堡来了(总共1个A类汉堡)

厨师乙:汉堡来了(总共1个B类汉堡)

厨师乙:汉堡来了(总共2个B类汉堡)

厨师甲:汉堡来了(总共2个A类汉堡)

厨师乙:汉堡来了(总共3个B类汉堡)

厨师甲:汉堡来了(总共3个A类汉堡)

厨师甲:汉堡来了(总共4个A类汉堡)

厨师乙:汉堡来了(总共4个B类汉堡)

厨师甲:汉堡来了(总共5个A类汉堡)

厨师乙:汉堡来了(总共5个B类汉堡)

厨师甲:汉堡来了(总共6个A类汉堡)

厨师乙:汉堡来了(总共6个B类汉堡)

厨师甲:汉堡来了(总共7个A类汉堡)

厨师乙:汉堡来了(总共7个B类汉堡)

厨师乙:汉堡来了(总共8个B类汉堡)

厨师甲:汉堡来了(总共8个A类汉堡)

厨师甲:汉堡来了(总共9个A类汉堡)

厨师乙:汉堡来了(总共9个B类汉堡)

所有的材料用完了!

厨师乙:汉堡来了(总共10个B类汉堡)


在编写线程的程序时,有很重要的一点,就是弄清楚交替执行的每个线程的执行条件,就像上面程序中所说,如果汉堡包没了,那么营业员就会对顾客说稍等。