生产者消费者问题已经是计算机领域在多线程方面的一个经典的问题了,这里提供一种Java的实现版本。

1.创建产品

这里我们直接使用数字来作为产品的代号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Product {

private int id;

public Product(int id) {
this.id = id;
}

@Override
public String toString() {
return "产品:" + id;
}

}

2.创建仓库

仓库是生产者消费者问题中的一个十分重要部件,因为不论是生产者还是消费者,他们使用的都是同一个仓库,这样才能让消费者可以消费生产者所生产的产品。仓库拥有两个方法:

  1. 获取并保存产品
  2. 输出自己的产品并从仓库把其剔除掉

这里通过队列这种数据结构来作为仓库的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class Repertory {

BlockingQueue<Product> queues = new LinkedBlockingQueue<Product>(10);

public void push(Product p) {
try {
queues.put(p);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

public Product pop() {
try {
return queues.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}

}

3.生产者消费者

生产者是生成产品并把其放到仓库中,而消费者则是从仓库中取出产品并消费掉

生产者:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class Producer implements Runnable {

private String name;

private Repertory repertory;

public Producer(String name, Repertory repertory) {
this.name = name;
this.repertory = repertory;
}

@Override
public void run() {
while (true) {
Product product = new Product((int) (Math.random() * 10000));
repertory.push(product);
System.out.println(name + ":开始生产 -->" + product);
// 防止显示太快
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

消费者:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class Consumer implements Runnable {

private String name;

private Repertory repertory;

public Consumer(String name, Repertory repertory) {
this.name = name;
this.repertory = repertory;
}

@Override
public void run() {
while (true) {
Product product = repertory.pop();
System.out.println(name + ":开始消费 -->" + product);
// 防止显示太快
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

}

4.测试,使生产者消费者模型运作起来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Test {

public static void main(String[] args) {
Repertory repertory = new Repertory();
ExecutorService service = Executors.newCachedThreadPool();
Producer p1 = new Producer("小1", repertory);
Producer p2 = new Producer("小2", repertory);
Producer p3 = new Producer("小3", repertory);
Consumer c1 = new Consumer("小A", repertory);
Consumer c2 = new Consumer("小B", repertory);
Consumer c3 = new Consumer("小C", repertory);
service.submit(p1);
service.submit(p2);
service.submit(p3);
service.submit(c1);
service.submit(c2);
service.submit(c3);
}

}

输出结果如下:

小3:开始生产 -->产品:5788
小C:开始消费 -->产品:5788
小1:开始生产 -->产品:5508
小2:开始生产 -->产品:2277
小A:开始消费 -->产品:5508
小B:开始消费 -->产品:2277
小3:开始生产 -->产品:7109
小B:开始消费 -->产品:4547
小2:开始生产 -->产品:4547
小1:开始生产 -->产品:6464
小A:开始消费 -->产品:6464
小C:开始消费 -->产品:7109
小3:开始生产 -->产品:863
小B:开始消费 -->产品:1262
小2:开始生产 -->产品:3230
小A:开始消费 -->产品:863
小1:开始生产 -->产品:1262
小C:开始消费 -->产品:3230
小B:开始消费 -->产品:9596
小C:开始消费 -->产品:6798
小A:开始消费 -->产品:9231
小2:开始生产 -->产品:9231
小3:开始生产 -->产品:9596
小1:开始生产 -->产品:6798

总结:

生产者消费模型其实还是比较简单的,其核心就是多个线程对一个资源的使用,然后完成我们想要的目标。多线程是计算机发展中的一个里程碑般发明,同时多线程也十分复杂并且充满挑战性的。关于更多的多线程相关的知识,可以搜寻一些操作系统的相关书籍来进行更加深入的学习。