Producer Consumer模式与Guarded Suspension模式类似(其实多线程模式都很类似,只是解决的特定问题域不同。个人意见^_^)。在Guarded Suspension模式中,我们没有对多个线程间所争用的资源进行数量的控制,而Producer Consumer模式则专门用来解决这一问题域。
下面我们加载一个场景,让大家和我一起来逐步理解什么是Producer Consumer模式:
2050年的某自动化生产工厂,生产机器人(Producer)负责生产产品(Product),生产的产品通过传送带(AutoCarryStrip)输送给产品测试机器人(这里可以将其看作产品的Consumer)进行测试,测试完成后装箱。这里,传送带由于负载原因,当承载量最大时,所有的工人必须停止生产产品。
我们回到现在,按OO的思想来进行抽象和分析,以下是我们需要实现的主要类、职责及其与其它类的关系(可以称其为CRC卡片):
类名 | Producer | 协作类及关系描述 |
职责 | 1. Product:产品,生产机器人的产出者 2. AutoCarryStrip:传送带,生产的产品将被放到其上,有最大承载量限制 | |
在传送带的承载量未达到最大时负责生产产品,并将其放置到传送带上。 |
类名 | Consumer | 协作类及关系描述 |
职责 | 1. Product:产品,从工作台上取下的待测试产品。 2. AutoCarryStrip:传送带,测试者将从其上取下产品 | |
负责在传送带上有产品时,取下产品进行测试装箱 |
类名 | AutoCarryStrip | 协作类及关系描述 |
职责 | 1. Product:产品 | |
负责运送产品,当达到最大承载量时通知生产机器人停止生产,在承载量为0时通知测试机器人停止测试。 |
可以看出,我们需要四个类来实现我们的这个自动化场景。如下:
Guarded Suspension加了一个双重的守护,专门用来守护边界。
2 *
3 */
4 package patterns.producerConsumer;
5
6 import java.util.Random;
7
8 /** */ /**
9 * producer<code>Producer</code> product a integer on IntTable until integer
10 * count more than MaxCount.
11 *
12 * @author Jackie Xie
13 *
14 */
15 public class Producer extends Thread {
16
17 private String name;
18 private AutoCarryStrip table;
19 private int totalCount =0;
20
21 public Producer(String name, AutoCarryStrip table) {
22 // TODO Auto-generated constructor stub
23 this.name = name;
24 this.table = table;
25 }
26
27 @Override
28 public void run() {
29 // TODO Auto-generated method stub
30 while (true) {
31 try {
32 Thread.sleep((long)(Math.random()*3000));
33 Thread.yield();
34 Product p = new Product(this.name);
35 System.out.println(this.name +" produced " + (++this.totalCount) );
36 table.produce(p);
37 } catch (Exception e) {
38 // TODO: handle exception
39 e.printStackTrace();
40 }
41 }
42 }
43
44}
45
1/** *//**
2 *
3 */
4package patterns.producerConsumer;
5
6/** *//**
7 * @author Jackie Xie
8 *
9 */
10public class Consumer extends Thread {
11
12 private int totalCount =0;
13
14 @Override
15 public void run() {
16 // TODO Auto-generated method stub
17 while (true) {
18 try {
19 Thread.sleep((long) Math.random() * 3000);
20 Thread.yield();
21 this.table.consume();
22 System.out.println(this.name + " consumed "
23 + (++this.totalCount) );
24 } catch (Exception e) {
25 // TODO: handle exception
26 e.printStackTrace();
27 }
28 }
29 }
30
31 private String name;
32
33 private AutoCarryStrip table;
34
35 public Consumer(String name, AutoCarryStrip table) {
36 // TODO Auto-generated constructor stub
37 this.name = name;
38 this.table = table;
39 }
40
41}
42
1package patterns.producerConsumer;
2
3import java.util.ArrayList;
4import java.util.List;
5import java.util.Random;
6
7public class AutoCarryStrip {
8
9 private int max;
10
11 /**//*
12 * workTable 维护一个工作桌列表,工作者生产的产品被放置到这里
13 */
14 private List<Product> productPool = new ArrayList<Product>();
15
16 private Random random = new Random();
17
18 public int getMax() {
19 return max;
20 }
21
22 public AutoCarryStrip(int max) {
23 // TODO Auto-generated constructor stub
24 this.max = max;
25 }
26
27 /** *//**
28 * 生产者生产的产品通过此方法被放置在产品桌上
29 *
30 * @param product
31 */
32 public synchronized void produce(Product product) {
33 while (productPool.size() >= max) {
34 try {
35 wait();
36 } catch (Exception e) {
37 // TODO: handle exception
38 System.out.println("table is full.");
39 }
40 }
41 productPool.add(product);
42 //System.out.println(product.toString() + " has put on work table.");
43 notifyAll();
44
45 }
46
47 public synchronized Product consume() {
48
49 while (productPool.size() <= 0) {
50 try {
51 wait();
52 } catch (Exception e) {
53 // TODO: handle exception
54 System.out.println("no product.");
55 }
56 }
57
58 Product p = productPool.remove(random.nextInt(productPool.size()));
59 notifyAll();
60 return p;
61
62 }
63}
64
1/** *//**
2 *
3 */
4package patterns.producerConsumer;
5
6/** *//**
7 * @author Jackie Xie
8 *
9 */
10public class Product {
11
12 private String name;
13 private static int productId =0;
14
15 public Product(String producerName) {
16 // TODO Auto-generated constructor stub
17 this.name = producerName + ++Product.productId;
18 }
19
20 public String getName() {
21 return name;
22 }
23 public String toString(){
24 return name;
25 }
26
27}
28
其实,通过以上代码,个人感觉这个模式其实就是给