Java 实践:生产者与消费者
实践项目:生产者与消费者【经典多线程问题】
问题引出:
生产者和消费者指的是两个不同的线程类对象,操作同一个空间资源的情况。
需求引出:
—— 生产者负责生产数据,消费者负责取走数据
—— 生产者生产完一组数据之后,消费者就要取走一组数据
设置三个类:数据类、生产类、消费类;生产和消费类是线程类,同时操作同一个数据类;生产类负责每次向数据类中写入一组数据;消费类负责每次从数据类中取出一组数据。
package hello;
class Info { // 数据类
private String title ;
private String content;
public void setTitle(String title) {
this.title = title ;
}
public String getTitle() {
return title ;
}
public String getContent() {
return content ;
}
public void setContent(String content) {
this.content = content ;
}
}
class Producer implements Runnable { // 生成者类(线程)
private Info info ;
public Producer(Info info) {
this.info = info ;
}
@Override
public void run() {
for (int x = 0 ; x < 100 ; x ++ ) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
if ( x % 2 == 0 ) {
this.info.setTitle("张三");
this.info.setContent("男");
} else {
this.info.setTitle("王五");
this.info.setContent("男");
}
}
}
}
class Consumer implements Runnable {
private Info info ;
public Consumer(Info info) {
this.info = info ;
}
@Override
public void run() {
for (int x = 0 ; x < 100 ; x ++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.info.getTitle() + "——" + this.info.getContent());
}
}
}
public class TestDemo {
public static void main(String[] args) throws Exception {
Info info = new Info() ;
new Thread(new Producer(info)).start();
new Thread(new Consumer(info)).start();
}
}
上例程序执行后,会发现“错位的现象”;出现类似数据为取走,就存入新的数据的错误。【不同步且异步现象导致】
package hello;
class Info { // 数据类
private String title ;
private String content;
public synchronized void set(String title , String content) {
this.title = title ;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.content = content ;
}
public synchronized void get() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.title + "——" + this.content);
}
}
class Producer implements Runnable { // 生成者类(线程)
private Info info ;
public Producer(Info info) {
this.info = info ;
}
@Override
public void run() {
for (int x = 0 ; x < 100 ; x ++ ) {
if ( x % 2 == 0 ) {
this.info.set("张三", "男");
} else {
this.info.set("李悦", "女");
}
}
}
}
class Consumer implements Runnable {
private Info info ;
public Consumer(Info info) {
this.info = info ;
}
@Override
public void run() {
for (int x = 0 ; x < 100 ; x ++) {
this.info.get();
}
}
}
public class TestDemo {
public static void main(String[] args) throws Exception {
Info info = new Info() ;
new Thread(new Producer(info)).start();
new Thread(new Consumer(info)).start();
}
}
通过“同步方法”,解决了数据不同步的问题,但是于此而来的问题就是:数据的重复操作。
针对上两例程序,我们通过Object类的支持,来解决数据重复操作的问题:
如果像上例的设计,需要在程序中加入一个等待机制;当数据未取则等待数据取出后在存入,当数据未存等待数据存入后取出。而Object类中提供有专门的“等待”。

等待: public final void wait() throws InterruptedException
唤醒第一个等待线程: public final void notify() ;
唤醒全部的等待进入: public final void notifyAll(); //优先级高越有可能先唤醒
通过Object的线程等待和唤醒功能完善程序:
package hello;
class Info { // 数据类
private String title ;
private String content;
private boolean flag = true ;
// true:表示可以生产,不可以取走
// false:表示不可以生产,可以取走
public synchronized void set(String title , String content) {
if (this.flag == false) { // 发现不可以生产,则等待线程
try {
super.wait(); // 通过super调用自己的超类(父类)Object类中的wait()方法等待线程
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.title = title ;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.content = content ;
this.flag = false ;// 修改标记
super.notify(); //唤醒其他等待线程
}
public synchronized void get() {
if (this.flag == true) {
try {
super.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.title + "——" + this.content);
this.flag = true ; //修改标记
super.notify(); // 唤醒其他线程
}
}
class Producer implements Runnable { // 生成者类(线程)
private Info info ;
public Producer(Info info) {
this.info = info ;
}
@Override
public void run() {
for (int x = 0 ; x < 100 ; x ++ ) {
if ( x % 2 == 0 ) {
this.info.set("张三", "男");
} else {
this.info.set("李悦", "女");
}
}
}
}
class Consumer implements Runnable {
private Info info ;
public Consumer(Info info) {
this.info = info ;
}
@Override
public void run() {
for (int x = 0 ; x < 100 ; x ++) {
this.info.get();
}
}
}
public class TestDemo {
public static void main(String[] args) throws Exception {
Info info = new Info() ;
new Thread(new Producer(info)).start();
new Thread(new Consumer(info)).start();
}
}
我们依靠Object类中的等待唤醒机制完成了代码的要求。
------------------------
Java 实践:生产者与消费者的更多相关文章
- Windows下RabbitMQ 的下载、配置、Java实现生产者和消费者例子
RabbitMQ是一个轻量级的消息代理中间件,支持多种消息通信协议,支持分布式部署,支持运行于多个操作系统,具有灵活.高可用等特性.RabbitMQ支持多种协议,其中最为重要的是高级消息队列协议(AM ...
- java实现生产者和消费者问题
Java实现生产者和消费者问题 欢迎访问我的个人博客,获取更多有用的东西 链接一 链接二 也可以关注我的微信订阅号:CN丶Moti
- Java实现生产者和消费者
生产者和消费者问题是操作系统的经典问题,在实际工作中也常会用到,主要的难点在于协调生产者和消费者,因为生产者的个数和消费者的个数不确定,而生产者的生成速度与消费者的消费速度也不一样,同时还要实现生产者 ...
- java之生产者与消费者
package com.produce; import java.util.LinkedList; import java.util.Queue; /*@author shijin * 生产者与消费者 ...
- java线 生产者和消费者
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGlhbmdydWkxOTg4/font/5a6L5L2T/fontsize/400/fill/I0JBQk ...
- Java实现生产者与消费者模式
生产者不断向队列中添加数据,消费者不断从队列中获取数据.如果队列满了,则生产者不能添加数据:如果队列为空,则消费者不能获取数据.借助实现了BlockingQueue接口的LinkedBlockingQ ...
- Java中生产者与消费者模式
生产者消费者模式 首先来了解什么是生产者消费者模式.该模式也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例.该问题描述了两个共享固定大小缓冲区的线 ...
- java之生产者和消费者问题
package testThread; public class Test3 { public static void main(String[] args) { Clerk c = new Cler ...
- 菜鸡的Java笔记 生产者与消费者
生产者与消费者 代码要求知道做什么用即可 线程间的通讯问题以及 Object 类的支持 基础模型 现在希望实现一种数据的生产和取出的操作 ...
- Java 多线程-生产者、消费者
一.整体代码 ThreadDemo.java public class ThreadDemo { public static void main(String[] args) { Godown god ...
随机推荐
- Asp.Net Core 内置IOC容器的理解
Asp.Net Core 内置IOC容器的理解 01.使用IOC容器的好处 对接口和实现类由原来的零散式管理,到现在的集中式管理. 对类和接口之间的关系,有多种注入模式(构造函数注入.属性注入等). ...
- Go-接口(作用类似python类中的多态)
一.定义接口 type Person interface { Run() //只要有run方法的都算 Person结构体 } //还有定义方法 type Person2 interface { Spe ...
- javaWeb核心技术第五篇之jQuery
- 概述 - jQuery是一个优秀的javascript框架(js类库),兼容css3和各大浏览器,提供dom,events,animate,ajax等简易的操作.并且jQuery有非常丰富的插件, ...
- Kibana中文汉化支持
Kibana从6.6.0版本开始支持中文 参考:https://github.com/anbai-inc/Kibana_Hanization 汉化方法如下: 以现行最新版本7.2.0为例,测试机器为W ...
- R Data Frame
https://www.datamentor.io/r-programming/data-frame/ Check if a variable is a data frame or not We ca ...
- 团队项目之Scrum1
小组:BLACK PANDA 时间:2019.11.16 部分 得分项 分数 完成内容 第 1 篇 Scrum 冲刺博客 各个成员在 Alpha 阶段认领的任务 3 明日各个成员的任务安排 3 用户登 ...
- 示例:Oracle表锁、行锁模拟和处理
for update模拟锁表 --session 1 SQL> select * from tt for update; --session 2 SQL> update tt set id ...
- django之查询操作及开启事务
目录 聚合查询 aggregate 聚合函数 分组查询 annotate F与Q查询 F查询 Q查询 ORM操作事务 django中开启事务 聚合查询 aggregate 操作外键字段管理数据的时候, ...
- 04-Node.js学习笔记-相对路径VS绝对路径
4.1相对路径VS绝对路径 大多数情况下使用绝对路径,因为相对路径有时候相对的是命令行工具的当前工作目录 在读取文件或者设置文件路径时都会选择绝对路径 4.2使用__dirname 获取当前文件所在的 ...
- Spring Cloud 服务之间调用
微服务之多个服务间调用 现在又一个学生微服务 user 和 学校微服务 school,如果user需要访问school,我们应该怎么做? 1.使用RestTemplate方式 添加config imp ...