首先我们根据梳理我们之前Android(java)学习笔记70中关于生产者和消费者程序思路:

下面我们就要重点介绍这个等待唤醒机制

第一步:还是先通过代码体现出等待唤醒机制

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();    }}

 1 package cn.itcast_05; 2  3 public class SetThread implements Runnable { 4  5     private Student s; 6     private int x = 0; 7  8     public SetThread(Student s) { 9         this.s = s;10     }11 12     @Override13     public void run() {14         while (true) {15             synchronized (s) {16                 //判断有没有17                 if(s.flag){18                     try {19                         s.wait(); //t1等着,释放锁20                     } catch (InterruptedException e) {21                         e.printStackTrace();22                     }23                 }24                 25                 if (x % 2 == 0) {26                     s.name = "林青霞";27                     s.age = 27;28                 } else {29                     s.name = "刘意";30                     s.age = 30;31                 }32                 x++; //x=133                 34                 //修改标记35                 s.flag = true;36                 //唤醒线程37                 s.notify(); //唤醒t2,唤醒并不表示你立马可以执行,必须还得抢CPU的执行权。38             }39             //t1有,或者t2有40         }41     }42 }

 1 package cn.itcast_05; 2  3 public class GetThread implements Runnable { 4     private Student s; 5  6     public GetThread(Student s) { 7         this.s = s; 8     } 9 10     @Override11     public void run() {12         while (true) {13             synchronized (s) {14                 if(!s.flag){15                     try {16                         s.wait(); //t2就等待了。立即释放锁。将来醒过来的时候,是从这里醒过来的时候17                     } catch (InterruptedException e) {18                         e.printStackTrace();19                     }20                 }21                 22                 System.out.println(s.name + "---" + s.age);23                 //林青霞---2724                 //刘意---3025                 26                 //修改标记27                 s.flag = false;28                 //唤醒线程29                 s.notify(); //唤醒t130             }31         }32     }33 }

1 package cn.itcast_05;2 3 public class Student {4     String name;5     int age;6     boolean flag; // 默认情况是没有数据,默认是false,如果是true,说明有数据7 }

接下来我们对唤醒机制代码进行优化

 1 package cn.itcast_07; 2  3 /* 4  * 分析: 5  *         资源类:Student     6  *         设置学生数据:SetThread(生产者) 7  *         获取学生数据:GetThread(消费者) 8  *         测试类:StudentDemo 9  * 10  * 问题1:按照思路写代码,发现数据每次都是:null---011  * 原因:我们在每个线程中都创建了新的资源,而我们要求的时候设置和获取线程的资源应该是同一个12  * 如何实现呢?13  *         在外界把这个数据创建出来,通过构造方法传递给其他的类。14  * 15  * 问题2:为了数据的效果好一些,我加入了循环和判断,给出不同的值,这个时候产生了新的问题16  *         A:同一个数据出现多次17  *         B:姓名和年龄不匹配18  * 原因:19  *         A:同一个数据出现多次20  *             CPU的一点点时间片的执行权,就足够你执行很多次。21  *         B:姓名和年龄不匹配22  *             线程运行的随机性23  * 线程安全问题:24  *         A:是否是多线程环境        是25  *         B:是否有共享数据        是26  *         C:是否有多条语句操作共享数据    是27  * 解决方案:28  *         加锁。29  *         注意:30  *             A:不同种类的线程都要加锁。31  *             B:不同种类的线程加的锁必须是同一把。32  * 33  * 问题3:虽然数据安全了,但是呢,一次一大片不好看,我就想依次的一次一个输出。34  * 如何实现呢?35  *         通过Java提供的等待唤醒机制解决。36  * 37  * 等待唤醒:38  *         Object类中提供了三个方法:39  *             wait():等待40  *             notify():唤醒单个线程41  *             notifyAll():唤醒所有线程42  *         为什么这些方法不定义在Thread类中呢?43  *             这些方法的调用必须通过锁对象调用,而我们刚才使用的锁对象是任意锁对象。44  *             所以,这些方法必须定义在Object类中。45  * 46  * 最终版代码中47  *         把Student的成员变量给私有的了。 48  *         把设置和获取的操作给封装成了功能,并加了同步。 49  *         设置或者获取的线程里面只需要调用方法即可。 50  */51 public class StudentDemo {52     public static void main(String[] args) {53         //创建资源54         Student s = new Student();55         56         //设置和获取的类57         SetThread st = new SetThread(s);58         GetThread gt = new GetThread(s);59 60         //线程类61         Thread t1 = new Thread(st);62         Thread t2 = new Thread(gt);63 64         //启动线程65         t1.start();66         t2.start();67     }68 }

 1 package cn.itcast_07; 2  3 public class SetThread implements Runnable { 4  5     private Student s; 6     private int x = 0; 7  8     public SetThread(Student s) { 9         this.s = s;10     }11 12     @Override13     public void run() {14         while (true) {15             if (x % 2 == 0) {16                 s.set("林青霞", 27);17             } else {18                 s.set("刘意", 30);19             }20             x++;21         }22     }23 }

 1 package cn.itcast_07; 2  3 public class GetThread implements Runnable { 4     private Student s; 5  6     public GetThread(Student s) { 7         this.s = s; 8     } 9 10     @Override11     public void run() {12         while (true) {13             s.get();14         }15     }16 }

 1 package cn.itcast_07; 2  3 public class Student { 4     private String name; 5     private int age; 6     private boolean flag; // 默认情况是没有数据,如果是true,说明有数据 7  8     public synchronized void set(String name, int age) { 9         // 如果有数据,就等待10         if (this.flag) {11             try {12                 this.wait();13             } catch (InterruptedException e) {14                 e.printStackTrace();15             }16         }17 18         // 设置数据19         this.name = name;20         this.age = age;21 22         // 修改标记23         this.flag = true;24         this.notify();25     }26 27     public synchronized void get() {28         // 如果没有数据,就等待29         if (!this.flag) {30             try {31                 this.wait();32             } catch (InterruptedException e) {33                 e.printStackTrace();34             }35         }36 37         // 获取数据38         System.out.println(this.name + "---" + this.age);39 40         // 修改标记41         this.flag = false;42         this.notify();43     }44 }

更多相关文章

  1. Android(安卓)Framework启动过程(android内核剖析笔记)
  2. android 延时 不用另起线程或timertask
  3. android体系架构
  4. 【android】ORMLite框架 的使用方法---给你的数据库操作插上翅膀
  5. Android面试题整理(一)
  6. android异步更新UI
  7. android存取数据方式:文件、SharedPreferences
  8. 关于android的listview的数据解析和性能优化问题
  9. mybatisplus的坑 insert标签insert into select无参数问题的解决

随机推荐

  1. 推荐阅读:Android开发者的博客
  2. android的消息处理机制(图+源码分析)——Lo
  3. Android事件分发机制四:学了事件分发有什
  4. [Android(安卓)Pro] Android(安卓)手机ro
  5. Android(安卓)10.0后创建文件createNewFi
  6. 安卓开发艺术探索!带你全面解析Android框
  7. Android事件分发机制四:学了事件分发有什
  8. Android中从本地未安装的APK动态加载类和
  9. GitHub最火的android 项目
  10. Android/iOS版Cortana 12.10「芝士早报」