菜鸡的Java笔记 生产者与消费者
生产者与消费者
代码要求知道做什么用即可
线程间的通讯问题以及 Object 类的支持
基础模型
现在希望实现一种数据的生产和取出的操作形式,即:有两个甚至更多的线程对象,这样的线程分为生产者线程和消费者线程
那么最理想的状态是生产者每生产完一条完整的数据之后,消费者就要取走这个数据,并且进行输出的打印
现在假设要输出的信息有这样两个:
title = 帅帅, content = 一个学生;
title = 可爱的小动物, content = 小猫咪;
范例:程序的初期实现
package cn.mysterious.actualcombat;
class Info{
private String title;
private String content;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
class Producptor implements Runnable{
private Info info = null;
public Producptor(Info info){
this.info = info;
}
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 50; i++) {
if (i % 2 == 0) { // 偶数
this.info.setTitle("帅帅");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.info.setContent("一个学生");
}else {
this.info.setTitle("可爱的动物");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.info.setContent("小猫咪");
}
}
} }
class Consumer implements Runnable{
private Info info = null;
public Consumer(Info info){
this.info = info;
}
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 50; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(this.info.getTitle() + "-->" + this.info.getContent());
}
}
}
public class ActualCombat{
public static void main(String[] args){
Info info = new Info();
Producptor p = new Producptor(info);
Consumer c = new Consumer(info);
new Thread(p).start();
new Thread(c).start(); }
}
通过以上的执行可以发现有两个问题:
第一:数据错位了
第二:重复生产,重复取出
解决数据不同步问题
要想解决同步问题一定使用同步代码块或者是同步方法,既然要同步,那么肯定要将设置属性和取得的属性的内容都统一交给 Info 完成
范例:
package cn.mysterious.actualcombat;
class Info{
private String title;
private String content;
public synchronized void set(String content, String title){
this.title = title;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.content = content;
}
public synchronized void get(){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(this.title + "-->" +this.content );
}
}
class Producptor implements Runnable{
private Info info = null;
public Producptor(Info info){
this.info = info;
}
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 50; i++) {
if (i % 2 == 0) { // 偶数
this.info.set("帅帅","一个学生");
}else {
this.info.set("可爱的动物","小猫咪");
}
}
} }
class Consumer implements Runnable{
private Info info = null;
public Consumer(Info info){
this.info = info;
}
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 50; i++) {
this.info.get();
}
}
}
public class ActualCombat{
public static void main(String[] args){
Info info = new Info();
Producptor p = new Producptor(info);
Consumer c = new Consumer(info);
new Thread(p).start();
new Thread(c).start(); }
}
所有的设置和取得数据的操作都交给了同步方法完成
现在同步问题解决了,但是重复问题更严重了
解决重复操作
如果要想解决重复问题,那么必须加入等待与唤醒的处理机制,而这样的操作方法是有 Object 类所提供的
在 Object 类中提供有如下几种方法:
等待: public final void wait() throws InterruptedException{}
唤醒第一个等待线程: public final void notify();
唤醒全部等待线程: public final void notifyAll();
范例:修改Info类
package cn.mysterious.actualcombat;
class Info{
private String title;
private String content;
private boolean flag = true;
// flag = true 表示可以生产,但是不允许取走数据
// flag = false 表示可以取走数据,但是不允许生产数据
public synchronized void set(String title, String content){
if (this.flag = false) { // 表示已经生产过了,还未取走
try {
super.wait(); // 等待
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} // 没有生产,可以生产
this.title = title;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.content = content;
this.flag = false;// 表示生产过了
super.notify();
}
public synchronized void get(){
if (this.flag = true) { // 此时应该生产,不应该取走数据
try {
super.wait(); // 等待
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(this.title + "-->" +this.content );
this.flag = true; // 表示取走了
super.notify();
}
}
class Producptor implements Runnable{
private Info info = null;
public Producptor(Info info){
this.info = info;
}
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 50; i++) {
if (i % 2 == 0) { // 偶数
this.info.set("帅帅","一个学生");
}else {
this.info.set("可爱的动物","小猫咪");
}
}
} }
class Consumer implements Runnable{
private Info info = null;
public Consumer(Info info){
this.info = info;
}
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 50; i++) {
this.info.get();
}
}
}
public class ActualCombat{
public static void main(String[] args){
Info info = new Info();
Producptor p = new Producptor(info);
Consumer c = new Consumer(info);
new Thread(p).start();
new Thread(c).start(); }
}
面试题:请解释 sleep() 与 wait() 的区别?
sleep() 是 Thread 类定义的方法,在休眠一定时间之后自己唤醒
wait() 是 Object 类定义的方法,表示线程要等待执行,必须通过 notify(),notifyAll() 方法来进行唤醒
总结
生产者和消费者这是一个模型,完整的体现了线程的同步, Object 类的支持
菜鸡的Java笔记 生产者与消费者的更多相关文章
- 菜鸡的Java笔记 - java 断言
断言:assert (了解) 所谓的断言指的是在程序编写的过程之中,确定代码执行到某行之后数据一定是某个期待的内容 范例:观察断言 public class Abnorma ...
- 菜鸡的Java笔记 - java 正则表达式
正则表达式 RegularExpression 了解正则表达式的好处 正则表达式的基础语法 正则表达式的具体操作 content (内容 ...
- 菜鸡的Java笔记 数字操作类
数字操作类 Math 类的使用 Random 类的使用 BigInteger 和 BigDecimal 类的使用 Math 是一 ...
- 菜鸡的Java笔记 - java 线程常用操作方法
线程常用操作方法 线程的命名操作,线程的休眠,线程的优先级 线程的所有操作方法几乎都在 Thread 类中定义好了 线程的命名和取得 ...
- 菜鸡的Java笔记 日期操作类
日期操作类 Date 类与 long 数据类型的转换 SimpleDateFormat 类的使用 Calendar 类的使用 如 ...
- 菜鸡的Java笔记 开发支持类库
开发支持类库 SupportClassLibrary 观察者设计模式的支持类库 content (内容) 什么是观察者设计模式呢? ...
- 菜鸡的Java笔记 简单JAVA 类的开发原则以及具体实现
/* 现在要求定义一个雇员信息类 在这个类之中包含有雇员编号 姓名 职位 基本工资 佣金等信息 对于此时给定要求实际上就是描述一类事物,而这样的程序类在在java之中可以将其称为简单java类 ...
- 菜鸡的Java笔记 - java 访问控制权限
java中四种访问控制权限的使用 内容 在java里面一共定义有四个权限,按照由小到大的顺序:private<defaule<prote ...
- 菜鸡的Java笔记 国际化程序实现原理
国际化程序实现原理 Lnternationalization 1. Locale 类的使用 2.国家化程序的实现,资源读取 所谓的国际化的程序 ...
随机推荐
- 使用 WPF + Chrome 内核实现 在线客服系统 的复合客服端程序
本系列文章详细介绍使用 .net core 和 WPF 开发 升讯威在线客服与营销系统 的过程.本产品已经成熟稳定并投入商用. 免费使用 & 私有化部署免费下载:https://docs.sh ...
- Linux 清空日志的五种方法
VIM 是linux下一款优秀的编辑器,但是上手难度略大,网络上可以找到的教程很多,快捷键也非常多,一时很难记住. 本文换一种思路,就是根据平时自己的常用需要,去反查VIM如何操作的,再记录下来,这样 ...
- java 从零开始手写 RPC (07)-timeout 超时处理
<过时不候> 最漫长的莫过于等待 我们不可能永远等一个人 就像请求 永远等待响应 超时处理 java 从零开始手写 RPC (01) 基于 socket 实现 java 从零开始手写 RP ...
- $\text {FWT}$学习笔记
\(\text {FWT}\) 学习笔记 正常项的\(\text {FWT}\) 在\(\text {OI}\)中,我们经常会碰到这种问题: 给出一个长度为\(n\)的序列\(a_{1,2,...,n ...
- Jenkins 进阶篇 - 单元测试覆盖率
我们做项目开发,肯定免不了要写单元测试,不管是 Java 项目.Python 项目.PHP 项目,甚至是 nodejs 项目,都应该要写单元测试,本小节就来介绍单元测试的覆盖率报告输出和展示,在后面的 ...
- 2020.12.20-Codeforces Round #105补题
B - Escape The princess is going to escape the dragon's cave, and she needs to plan it carefully. Th ...
- 原生js-返回顶部
html部分: <body style="height:2000px"> <div id="div1"> 返回顶部 </div&g ...
- docker逃逸漏洞复现(CVE-2019-5736)
漏洞概述 2019年2月11日,runC的维护团队报告了一个新发现的漏洞,SUSE Linux GmbH高级软件工程师Aleksa Sarai公布了影响Docker, containerd, Podm ...
- UltraSoft - Alpha - Scrum Meeting 7
Date: Apr 22th, 2020. Scrum 情况汇报 进度情况 组员 负责 昨日进度 后两日任务 CookieLau PM 完成课程中心的json格式传递 完成邮箱验证机制 刘zh 前端 ...
- windows下wchar_t的问题
使用vs新建工程或者编译工程的时候默认在编译设置里面讲wchar_t设置为内置类型,如下图: 但是在编译相互依赖的工程的时候,如果有的工程不将wchar_t设置为内置类型的时候,将会出现链接错误,需要 ...