生产者-消费者问题(计算机系统中的许多问题都可归结为此问题)描述如下:生产者与消费者可以通过一个环形缓冲池联系起来,环形缓冲池由几个大小相等的缓冲块组成,每个缓冲块容纳一个产品。每个生产者可不断地每次往缓冲池中送一个生产产品,而每个消费者则可不断地每次从缓冲池中取出一个产品。 编写程序模拟多个生产者和多个消费者共享缓冲池的生产和消费过程。 要求: 1. 设计信号量用于进行生产者-消费者、生产者-生产者、消费者-消费者之间的同步控制; 2. 创建多个(不少于5个)进程或者线程模拟生产者和消费者; 3. 缓冲池大小定义在10-20,缓冲块中的产品为数据; 4. 程序运行结果能实时显示缓冲池中生产和消费产品的过程,包括断点、推进时间、次序等,编程语言可选用Java。
时间: 2024-02-12 13:03:39 浏览: 68
以下是使用Java语言实现的多线程生产者-消费者问题的示例代码:
```java
import java.util.Random;
import java.util.concurrent.Semaphore;
public class ProducerConsumer {
private static final int BUFFER_SIZE = 10; // 缓冲池大小
private static final int NUM_PRODUCERS = 5; // 生产者数量
private static final int NUM_CONSUMERS = 5; // 消费者数量
private static final int MAX_ITEM = 100; // 产品最大值
private static int[] buffer = new int[BUFFER_SIZE]; // 缓冲池
private static Semaphore emptySema = new Semaphore(BUFFER_SIZE); // 空闲缓冲块信号量
private static Semaphore fullSema = new Semaphore(0); // 满缓冲块信号量
private static Semaphore putMutex = new Semaphore(1); // 生产者信号量
private static Semaphore getMutex = new Semaphore(1); // 消费者信号量
public static void main(String[] args) {
Thread[] producers = new Thread[NUM_PRODUCERS];
Thread[] consumers = new Thread[NUM_CONSUMERS];
for (int i = 0; i < NUM_PRODUCERS; i++) {
producers[i] = new Producer(i);
producers[i].start();
}
for (int i = 0; i < NUM_CONSUMERS; i++) {
consumers[i] = new Consumer(i);
consumers[i].start();
}
try {
for (int i = 0; i < NUM_PRODUCERS; i++) {
producers[i].join();
}
for (int i = 0; i < NUM_CONSUMERS; i++) {
consumers[i].join();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
static class Producer extends Thread {
private int id;
public Producer(int id) {
this.id = id;
}
public void run() {
while (true) {
try {
Thread.sleep(new Random().nextInt(1000)); // 随机等待一段时间
emptySema.acquire(); // 获取空闲缓冲块
putMutex.acquire(); // 获取生产者信号量
int index = putItem(); // 生产产品并放入缓冲池
putMutex.release(); // 释放生产者信号量
fullSema.release(); // 增加满缓冲块计数
System.out.printf("生产者%d在缓冲块%d中生产了%d\n", id, index, buffer[index]);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private int putItem() {
int item = new Random().nextInt(MAX_ITEM);
for (int i = 0; i < BUFFER_SIZE; i++) {
if (buffer[i] == 0) {
buffer[i] = item;
return i;
}
}
return -1;
}
}
static class Consumer extends Thread {
private int id;
public Consumer(int id) {
this.id = id;
}
public void run() {
while (true) {
try {
Thread.sleep(new Random().nextInt(1000)); // 随机等待一段时间
fullSema.acquire(); // 获取满缓冲块
getMutex.acquire(); // 获取消费者信号量
int index = getItem(); // 从缓冲池中消费产品
getMutex.release(); // 释放消费者信号量
emptySema.release(); // 增加空闲缓冲块计数
System.out.printf("消费者%d从缓冲块%d中取出了%d\n", id, index, buffer[index]);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private int getItem() {
for (int i = 0; i < BUFFER_SIZE; i++) {
if (buffer[i] != 0) {
int item = buffer[i];
buffer[i] = 0;
return i;
}
}
return -1;
}
}
}
```
在这个示例代码中,我们使用了`Semaphore`来创建信号量。`emptySema`表示空闲缓冲块的数量,`fullSema`表示满缓冲块的数量,`putMutex`和`getMutex`分别是生产者和消费者的信号量。在生产者和消费者的`run`方法中,我们使用`acquire`和`release`方法来获取和释放信号量和缓冲块。在生产者的`putItem`方法中,我们随机生成一个产品并将其放入缓冲池中,然后返回该产品所在的缓冲块的索引。在消费者的`getItem`方法中,我们查找第一个非空缓冲块并从中取出产品,然后将该缓冲块清空,并返回该缓冲块的索引。
运行示例代码,可以看到生产者和消费者在缓冲池中生产和消费产品的过程。由于生产者和消费者是并发运行的,因此可能会出现一些断点和次序的变化。但是,由于我们使用了信号量来进行同步控制,因此缓冲池中的产品数量始终不会超过其容量限制。
阅读全文