# 基于JAVA的生产者消费者问题
# 一、需求分析
为了更好地理解进程同步的机制和过程,决定设计实现生产者消费者问题的解决,以实现进程的同步控制。
题目描述:有n个生产者在生产产品,这些产品将提供给m个消费者去消费,为了使生产者和消费者能并发执行,在两者之间设置一个具有k个缓冲区的缓冲池,生产者将它生产的产品放入一个缓冲区中,消费者可以从缓冲区中取走产品进行消费,显然生产者和消费者之间必须保持同步,即不允许消费者到一个空的缓冲区中取产品,也不允许生产者向一个已经放入产品的缓冲区中再次投放产品。
由此为题,编程实现:输入生产者个数、消费者个数、缓冲区个数、每个生产者生产产品的个数,实现输出:生产者消费者同步执行情况下的具体执行过程。
# 二、概要设计
为了简化编码过程,将题目转变成由线程实现同步,以达到相同的目标,并采用Java实现,在控制台将程序执行的整个过程生产者消费者的执行过程输出出来。
设计初步方案:使用Java的Thread来实现线程的生成,并继承Thread类,重写run()方法,来设定线程中的执行代码。
**生产者流程图**
![](http://www.writebug.com/myres/static/uploads/2021/10/19/789350a19dde5501ab913b19f9111ea3.writebug)
**消费者流程图**
![](http://www.writebug.com/myres/static/uploads/2021/10/19/f3e52800d96c9c00ce715a28f35f0793.writebug)
# 三、详细设计
## 3.1 设计思想
同步机制,首先采用Java的synchronized来实现对缓冲区的互斥访问,再设置一个信号量来实现对缓冲区为空和为满的状态标记。生产者通过在synchronized同步代码块中先对缓冲区是否为满作出判断,若缓冲区为满,将当前线程添加到缓冲区的等待列表中,线程阻塞,并且在每次生产完一件产品之后唤醒缓冲区的所有等待列表;消费者通过在synchronized同步代码块中先对缓冲区是否为空作出判断,若缓冲区为空,将当前线程加入到缓冲区的等待列表中,并且在每次消费完一件产品之后唤醒缓冲区的所有等待列表。
## 3.2 模块设计
### 3.2.1 消费者线程实现类
```java
public class Consumer implements Runnable {
private String name;// 线程名称
private List<Object> list;// 共享区
public Consumer(String name, List<Object> list) {
this.name = name;
this.list = list;
}
@Override
public void run() {
loop: while (true) {
// 控制权在消费者
synchronized (list) {// 同步块,实现线程互斥
while (list.size() <= 0)
// 没产品了
try {
// 进程还未完成
if (!Main.completed)
list.wait();
else
// 进程完成,跳出外循环,结束该线程
break loop;
} catch (InterruptedException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
// 缓冲区还有产品
list.remove(list.size() - 1);
System.out.println("线程:" + name + " 消费了1个产品,原来有: "
+ (list.size() + 1) + " ,当前产品总数:" + list.size());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 唤醒其他线程
list.notifyAll();
}
}
}
}
```
### 3.2.2 生产者线程实现类
```java
public class Producer implements Runnable {
private String name;// 线程名称
private List<Object> list;// 共享区
private int productCount;// 每个生产者生产产品数
private int producerCount;// 生产者总个数
public Producer(String name, int productCount, List<Object> list,
int producerCount) {
this.name = name;
this.list = list;
this.productCount = productCount;
this.producerCount = producerCount;
}
@Override
public void run() {
int i = 0;
// 生产productCount个产品
while (i < productCount) {
// 控制权在生产者
synchronized (list) {// 同步块,实现线程互斥
while (list.size() >= Main.bufferCount)
// 缓冲区满,等待
try {
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
// 缓冲区还有空间
list.add(new Object());
System.out.println("线程:" + name + " 生产了1个产品,原来有: "
+ (list.size() - 1) + " ,当前产品总数:" + list.size()
+ " ,还需生产产品数:" + (productCount - i - 1));
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 唤醒其他线程
list.notifyAll();
}
i++;
}
// 生产者完成任务,刷新标记位
synchronized (Main.producerCompleted) {
Main.producerCompleted.producerCompleted++;// 生产完成,记录标记
// 所有生产者均完成任务
if (Main.producerCompleted.producerCompleted == this.producerCount) {
// 进程标记完成
Main.completed = true;
// 通知消费者结束线程
synchronized (list) {
list.notifyAll();
}
}
}
}
}
```
### 3.2.3 进程结束信号量
```java
public class Complete {
public int producerCompleted;// 生产完成的生产者数
}
```
### 3.2.4 执行代码
```java
public class Main {
public static int bufferCount = 10;// 缓冲区,默认为10
public static List<Object> list = new ArrayList<Object>();// 生产好的产品列表
public static Complete producerCompleted = new Complete();// 标记生产完成了的生产者数目
public static boolean completed = false;// 标记本进程是否完成任务,完成了通知消费者结束线程
public static void main(String[] args) {
producerCompleted.producerCompleted = 0;// 标记生产完成了的生产者数目,刚开始为0
Scanner scanner = new Scanner(System.in);
System.out.println("请输入生产者个数:");
int producerCount = scanner.nextInt();
System.out.println("请输入消费者个数:");
int consumerCount = scanner.nextInt();
System.out.println("请输入缓冲区个数:");
bufferCount = scanner.nextInt();
System.out.println("请输入每个生产者生产产品个数:");
int productCount = scanner.nextInt();
for (int i = 1; i <= producerCount; i++) {
Thread productThread = new Thread(new Producer("生产者" + i,
productCount, list,producerCount));
productThread.start();
}
for (int i = 1; i <= consumerCount; i++) {
Thread consumerThread = new Thread(new Consumer("消费者" + i, list));
consumerThread.start();
}
}
}
```
# 四、调试分析
**测试数据**
- 生产者数量:10
- 消费者数量:5
- 缓冲区数量:10
- 每个生产者生产产品数:3
**执行结果**
![](http://www.writebug.com/myres/static/uploads/2021/10/19/9546b3e47351fc28420799053a53238b.writebug)
![](http://www.writebug.com/myres/static/uploads/2021/10/19/050a6d3956ff6e8446149a3d9d9d76fe.writebug)
![](http://www.writebug.com/myres/static/uploads/2021/10/19/77ba3eb4117fd8b7bf605e4a1369d2e0.writebug)
**结果分析**
每当缓冲区产品数到了10,也就是满,生产者就会停下来让消费者消费,每当缓冲区产品为0时,消费者就会停下来等待生产者生产产品。
# 五、用户使用说明
在Eclipse中点击 File——Import——Existing Projects into WorkSpace——Browser——找到ProductorConsumer文件夹的路径位置,将本工程导入到Eclipse中,然后右键工程 Run As Java Application,程序便开始执行,根据控制台文字提示输入相应的生产者数量,消费者数量,缓冲区个数,每个生产者生产产品数,便可看见程序的执行过程。
环境说明:本工程建立在 JDK1.7 环境下。
没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
收起资源包目录
9131015839029126.zip (14个子文件)
producer-consumer-problem
LICENSE 1KB
生产者-消费者问题
ProductorConsumer
.classpath 295B
.settings
org.eclipse.jdt.core.prefs 587B
src
com
silence
thread
Complete.java 160B
Consumer.java 1KB
Producer.java 2KB
Main.java 1KB
bin
com
silence
thread
Complete.class 319B
Consumer.class 2KB
Main.class 2KB
Producer.class 2KB
.project 376B
README.md 8KB
生产者消费者课程设计报告.docx 259KB
共 14 条
- 1
资源评论
工具盒子
- 粉丝: 60
- 资源: 1313
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- 高光谱数据集(.mat.csv)-科研学术
- 基于JavaScript和CSS的母婴之家网页设计源码 - myzj
- WX小程序源码无后台京东白条
- WX小程序源码无后台简易计算器
- 基于SpringBoot和Vue的Fastcms前后端分离CMS系统设计源码 - fastcms
- WX小程序源码无后台会议精灵
- 基于Java和Javascript的工程建设综合管理系统材料管理模块设计源码 - material
- c51_2_2.c
- 凡客vancl商城的商品分类-产品搜索-产品详情-评论的抓取php程序压缩包
- ASCII American Standard Code for Information Interchange
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功