Android(java)学习笔记71:生产者和消费者之等待唤醒机制
1. 首先我们根据梳理我们之前Android(java)学习笔记70中,关于生产者和消费者程序思路:

2. 下面我们就要重点介绍这个等待唤醒机制:
(1)第一步:还是先通过代码体现出等待唤醒机制
下面是测试类:
package cn.itcast_05; /*
* 分析:
* 资源类:Student
* 设置学生数据:SetThread(生产者)
* 获取学生数据:GetThread(消费者)
* 测试类:StudentDemo
*
* 问题1:按照思路写代码,发现数据每次都是:null---0
* 原因:我们在每个线程中都创建了新的资源,而我们要求的时候设置和获取线程的资源应该是同一个
* 如何实现呢?
* 在外界把这个数据创建出来,通过构造方法传递给其他的类。
*
* 问题2:为了数据的效果好一些,我加入了循环和判断,给出不同的值,这个时候产生了新的问题
* A:同一个数据出现多次
* B:姓名和年龄不匹配
* 原因:
* A:同一个数据出现多次
* CPU的一点点时间片的执行权,就足够你执行很多次。
* B:姓名和年龄不匹配
* 线程运行的随机性
* 线程安全问题:
* A:是否是多线程环境 是
* B:是否有共享数据 是
* C:是否有多条语句操作共享数据 是
* 解决方案:
* 加锁。
* 注意:
* A:不同种类的线程都要加锁。
* B:不同种类的线程加的锁必须是同一把。
*
* 问题3:虽然数据安全了,但是呢,一次一大片不好看,我就想依次的一次一个输出。
* 如何实现呢?
* 通过Java提供的等待唤醒机制解决。
*
* 等待唤醒:
* Object类中提供了三个方法:
* wait():等待
* notify():唤醒单个线程
* notifyAll():唤醒所有线程
* 为什么这些方法不定义在Thread类中呢?
* 这些方法的调用必须通过锁对象调用,而我们刚才使用的锁对象是任意锁对象。
* 所以,这些方法必须定义在Object类中。
*/
public class StudentDemo {
public static void main(String[] args) {
//创建资源
Student s = new Student(); //设置和获取的类
SetThread st = new SetThread(s);
GetThread gt = new GetThread(s); //线程类
Thread t1 = new Thread(st);
Thread t2 = new Thread(gt); //启动线程
t1.start();
t2.start();
}
}
下面是生产者线程类:
package cn.itcast_05;
public class SetThread implements Runnable {
private Student s;
private int x = 0;
public SetThread(Student s) {
this.s = s;
}
@Override
public void run() {
while (true) {
synchronized (s) {
//判断有没有
if(s.flag){
try {
s.wait(); //t1等着,释放锁
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (x % 2 == 0) {
s.name = "林青霞";
s.age = 27;
} else {
s.name = "刘意";
s.age = 30;
}
x++; //x=1
//修改标记
s.flag = true;
//唤醒线程
s.notify(); //唤醒t2,唤醒并不表示你立马可以执行,必须还得抢CPU的执行权。
}
//t1有,或者t2有
}
}
}
下面是消费者线程类:
package cn.itcast_05;
public class GetThread implements Runnable {
private Student s;
public GetThread(Student s) {
this.s = s;
}
@Override
public void run() {
while (true) {
synchronized (s) {
if(!s.flag){
try {
s.wait(); //t2就等待了。立即释放锁。将来醒过来的时候,是从这里醒过来的时候
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(s.name + "---" + s.age);
//林青霞---27
//刘意---30
//修改标记
s.flag = false;
//唤醒线程
s.notify(); //唤醒t1
}
}
}
}
Student类:
package cn.itcast_05;
public class Student {
String name;
int age;
boolean flag; // 默认情况是没有数据,默认是false,如果是true,说明有数据
}
(2)接下来我们对唤醒机制代码进行优化:
下面是测试类:
package cn.itcast_07; /*
* 分析:
* 资源类:Student
* 设置学生数据:SetThread(生产者)
* 获取学生数据:GetThread(消费者)
* 测试类:StudentDemo
*
* 问题1:按照思路写代码,发现数据每次都是:null---0
* 原因:我们在每个线程中都创建了新的资源,而我们要求的时候设置和获取线程的资源应该是同一个
* 如何实现呢?
* 在外界把这个数据创建出来,通过构造方法传递给其他的类。
*
* 问题2:为了数据的效果好一些,我加入了循环和判断,给出不同的值,这个时候产生了新的问题
* A:同一个数据出现多次
* B:姓名和年龄不匹配
* 原因:
* A:同一个数据出现多次
* CPU的一点点时间片的执行权,就足够你执行很多次。
* B:姓名和年龄不匹配
* 线程运行的随机性
* 线程安全问题:
* A:是否是多线程环境 是
* B:是否有共享数据 是
* C:是否有多条语句操作共享数据 是
* 解决方案:
* 加锁。
* 注意:
* A:不同种类的线程都要加锁。
* B:不同种类的线程加的锁必须是同一把。
*
* 问题3:虽然数据安全了,但是呢,一次一大片不好看,我就想依次的一次一个输出。
* 如何实现呢?
* 通过Java提供的等待唤醒机制解决。
*
* 等待唤醒:
* Object类中提供了三个方法:
* wait():等待
* notify():唤醒单个线程
* notifyAll():唤醒所有线程
* 为什么这些方法不定义在Thread类中呢?
* 这些方法的调用必须通过锁对象调用,而我们刚才使用的锁对象是任意锁对象。
* 所以,这些方法必须定义在Object类中。
*
* 最终版代码中:
* 把Student的成员变量给私有的了。
* 把设置和获取的操作给封装成了功能,并加了同步。
* 设置或者获取的线程里面只需要调用方法即可。
*/
public class StudentDemo {
public static void main(String[] args) {
//创建资源
Student s = new Student(); //设置和获取的类
SetThread st = new SetThread(s);
GetThread gt = new GetThread(s); //线程类
Thread t1 = new Thread(st);
Thread t2 = new Thread(gt); //启动线程
t1.start();
t2.start();
}
}
生产者线程类:
package cn.itcast_07;
public class SetThread implements Runnable {
private Student s;
private int x = 0;
public SetThread(Student s) {
this.s = s;
}
@Override
public void run() {
while (true) {
if (x % 2 == 0) {
s.set("林青霞", 27);
} else {
s.set("刘意", 30);
}
x++;
}
}
}
消费者线程类:
package cn.itcast_07;
public class GetThread implements Runnable {
private Student s;
public GetThread(Student s) {
this.s = s;
}
@Override
public void run() {
while (true) {
s.get();
}
}
}
Student类,同时Student内部封装了Student的两个同步方法(生产Student 和 消费Student)
package cn.itcast_07;
public class Student {
private String name;
private int age;
private boolean flag; // 默认情况是没有数据,如果是true,说明有数据
public synchronized void set(String name, int age) {
// 如果有数据,就等待
if (this.flag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 设置数据
this.name = name;
this.age = age;
// 修改标记
this.flag = true;
this.notify();
}
public synchronized void get() {
// 如果没有数据,就等待
if (!this.flag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 获取数据
System.out.println(this.name + "---" + this.age);
// 修改标记
this.flag = false;
this.notify();
}
}
3. sleep和wait的区别有:
(1)这两个方法来自不同的类,分别是Thread和Object
(2)最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。
(3)wait,notify 和 notifyAll 只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用。
synchronized(x){
x.notify()
//或者wait()
}
(4)sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常。
Android(java)学习笔记71:生产者和消费者之等待唤醒机制的更多相关文章
- java多线程中的生产者与消费者之等待唤醒机制@Version1.0
一.生产者消费者模式的学生类成员变量生产与消费demo,第一版1.等待唤醒: Object类中提供了三个方法: wait():等待 notify():唤醒单个线程 notify ...
- java多线程中的生产者与消费者之等待唤醒机制@Version2.0
二.生产者消费者模式的学生类成员变量生产与消费demo, @Version2.0 在学生类中添加同步方法:synchronized get()消费者,synchronized set()生产者 最终版 ...
- Android(java)学习笔记11:生产者和消费者之等待唤醒机制
1. 首先我们根据梳理我们之前Android(java)学习笔记70中,关于生产者和消费者程序思路: 2. 下面我们就要重点介绍这个等待唤醒机制: (1)第一步:还是先通过代码体现出等待唤醒机制 下面 ...
- java ->多线程_线程同步、死锁、等待唤醒机制
线程安全 如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的. l 我们通过一个案例,演示线 ...
- 2.5多线程(Java学习笔记)生产者消费者模式
一.什么是生产者消费者模式 生产者生产数据存放在缓冲区,消费者从缓冲区拿出数据处理. 可能大家会问这样有何好处? 1.解耦 由于有了缓冲区,生产者和消费者之间不直接依赖,耦合度降低,便于程序拓展和维护 ...
- java多线程(死锁,lock接口,等待唤醒机制)
一.Lock接口 常用方法 Lock提供了一个更加面对对象的锁,在该锁中提供了更多的操作锁的功能. 使用Lock接口,以及其中的lock()方法和unlock()方法替代同步,对电影院卖票案例中Tic ...
- Java第二十五天,多线程之等待唤醒机制
当线程被创建并且被启动之后,它既不是一启动就进入了执行状态,也不是一直处于执行状态,而是具有以下多种状态: 这六种状态之间的转换关系如下: 1.等待唤醒机制 注意: (1)两个线程之间必须用同步代码块 ...
- java之等待唤醒机制(线程之间的通信)
线程间通信 概念:多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同.比如:线程A用来生成包子的,线程B用来吃包子的,包子可以理解为同一资源,线程A与线程B处理的动作,一个是生产,一个是消 ...
- java学习笔记之基础篇
java选择语句之switch //switch可以用于等值判断 switch (e) //int ,或则可以自动转化成int 的类型,(byte char short)枚举jdk 7中可以防止字 ...
随机推荐
- ***JAVA多线程的应用场景和应用目的举例
多线程使用的主要目的在于: 1.吞吐量:你做WEB,容器帮你做了多线程,但是他只能帮你做请求层面的.简单的说,可能就是一个请求一个线程.或多个请求一个线程.如果是单线程,那同时只能处理一个用户的请求. ...
- Buffer -nodejs
纯 JavaScript 对 Unicode 友好但是无法很好地处理二进制数据.当我们面对类似 TCP 流或文件系统时,是需要处理八位流的.Node 有几种操作.创建以及消费八位流的策略.原始数据保存 ...
- ESXI安装
1.设置从USB启动 按DEL进入BIOS设置 参考http://www.upanok.com/jiaocheng/68.html 先插入USB,在选择ADVANCAED BIOS FEATURES ...
- Jquery类级别与对象级别插件开发
jQuery插件的开发包括两种: 一种是类级别的插件开发,即给jQuery添加新的全局函数,相当于给jQuery类本身添加方法.jQuery的全局函数就是属于jQuery命名空间的函数,另一种是对象级 ...
- mac搭建PHP开发环境
在Mac系统上搭建Php服务器环境: LAMP: Linux Apache MySQL PHP MAMP: MACOS APACHE(自带) MYSQL(需自己安装) PHP(自带) 一.APACHE ...
- homework-附加题:第12章基本数据类型阅读总结
基本数据类型是构建其他所有数据类型的构造块,本人认为这部分是计算机编程的基础,值得得到大家的注意. 首先,在本章中作者提到了避免使用magic number.使用magic number这种做法是极其 ...
- 【转】Xcode 插件优缺点对比(推荐 20 款插件)
[转自]http://www.cnblogs.com/dsxniubility/p/5099191.html 1.Alcatraz 类似于管理第三方库的cocoapods,管理插件也有个Alcatra ...
- 【转】iOS 硬件授权检测:定位服务、通讯录、日历、提醒事项、照片、蓝牙共享、麦克风、相机等
iOS系统版本的不断升级的前提,伴随着用户使用设备的安全性提升,iOS系统对于App需要使用的硬件限制也越来越严格,App处理稍有不妥,轻则造成功能不可用用户还不知道,重则会造成App Crash. ...
- SQl函数的写法
USE [ChangHong_612]GO/****** Object: UserDefinedFunction [dbo].[FN_GetProdQty] Script Date: 10/08/20 ...
- 访问修饰符与可选修饰符static的使用
在Java中修饰符较多,在这里简单说一说几个访问修饰符的选择使用,和可选修饰符static的使用. 一.访问修饰符:这是Java里用来控制访问类及类的方法.变量的访问权限,从而达到只暴露接口,来隐藏内 ...