菜鸡的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.国家化程序的实现,资源读取 所谓的国际化的程序 ...
随机推荐
- HTML常用的css属性(及其简写)
这篇文章主要介绍几个常用css属性和简写 本文目录: 1.背景属性 2.边框属性 3.字体属性 4.外边距 5.填充 6.颜色 1.background[背景属性] background-color ...
- mysql从零开始之MySQL 删除数据库
MySQL 删除数据库 使用普通用户登陆 MySQL 服务器,你可能需要特定的权限来创建或者删除 MySQL 数据库,所以我们这边使用 root 用户登录,root 用户拥有最高权限. 在删除数据库过 ...
- Linux Bash命令杂记(cut sort uniq wc tee)
Linux Bash命令杂记(cut sort uniq wc tee) 数据流重定向 标准输入(stdin):代码为0,使用<或<<: 标准输出(stdout):代码为1,使用&g ...
- javascriptRemke之深入迭代
javascriptRemke之深入迭代 前言:"迭代"意为按照顺序反复多次执行一段程序,ECMAscript6中新增了两个高级特性:迭代器与生成器,使用这两个特性能更高效地实现迭 ...
- UI BLOCK自定义枚举控件的宽度
三步: 1.修改PresentationStyle属性为Radio Box 2.修改NumberOfColumns属性为指定的宽度(显示字符的个数) 3.将PresentationStyle属性改回O ...
- verilog specify
specify block用来描述从源点(source:input/inout port)到终点(destination:output/inout port)的路径延时(path delay),由sp ...
- 封装一个的toast弹出框(vue项目)
逆风的方向,更适合飞翔 实现效果 实现步骤 先写出一个toast组件 // Toast.vue <template> <div id="toast" :class ...
- the Agiles Scrum Meeting 10
会议时间:2020.4.18 20:00 1.每个人的工作 今天已完成的工作 个人结对项目增量开发组:完成自动创建仓库功能 issues:增量组:准备评测机制,增加仓库自动创建和管理 团队项目增量开发 ...
- [火星补锅] 非确定性有穷状态决策自动机练习题Vol.3 T3 && luogu P4211 [LNOI2014]LCA 题解
前言: 这题感觉还是很有意思.离线思路很奇妙.可能和二次离线有那么一点点相似?当然我不会二次离线我就不云了. 解析: 题目十分清真. 求一段连续区间内的所有点和某个给出的点的Lca的深度和. 首先可以 ...
- Linux多线程编程实例解析
Linux系统下的多线程遵循POSIX线程接口,称为 pthread.编写Linux下的多线程程序,需要使用头文件pthread.h,连接时需要使用库libpthread.a.顺便说一下,Linux ...