首页 > 编程语言 > 详细

多线程之Java中的等待唤醒机制

时间:2018-12-12 23:28:48      阅读:185      评论:0      收藏:0      [点我收藏+]

  多线程的问题中的经典问题是生产者和消费者的问题,就是如何让线程有序的进行执行,获取CPU执行时间片的过程是随机的,如何能够让线程有序的进行,Java中提供了等待唤醒机制很好的解决了这个问题!

  生产者消费者经典的线程中的问题其实是解决线程中的通讯问题,就是不同种类的线程针对同一资源的操作,这里其实有一张图很好的阐述了这其中的问题:

技术分享图片

  1 //代码中的实体类
  2 public class Student {
  3     String name;
  4     int age;
  5     boolean flag; // 默认情况是没有数据,如果是true,说明有数据
  6 }
  7 
  8 public class SetThread implements Runnable {
  9 
 10     private Student s;
 11     private int x = 0;
 12 
 13     public SetThread(Student s) {
 14         this.s = s;
 15     }
 16 
 17     @Override
 18     public void run() {
 19         while (true) {
 20             synchronized (s) {
 21                 //判断有没有
 22                 if(s.flag){
 23                     try {
 24                         s.wait(); //t1等着,释放锁
 25                     } catch (InterruptedException e) {
 26                         e.printStackTrace();
 27                     }
 28                 }
 29                 
 30                 if (x % 2 == 0) {
 31                     s.name = "林青霞";
 32                     s.age = 27;
 33                 } else {
 34                     s.name = "刘意";
 35                     s.age = 30;
 36                 }
 37                 x++; //x=1
 38                 
 39                 //修改标记
 40                 s.flag = true;
 41                 //唤醒线程
 42                 s.notify(); //唤醒t2,唤醒并不表示你立马可以执行,必须还得抢CPU的执行权。
 43             }
 44             //t1有,或者t2有
 45         }
 46     }
 47 }
 48 
 49 public class GetThread implements Runnable {
 50     private Student s;
 51 
 52     public GetThread(Student s) {
 53         this.s = s;
 54     }
 55 
 56     @Override
 57     public void run() {
 58         while (true) {
 59             synchronized (s) {
 60                 if(!s.flag){
 61                     try {
 62                         s.wait(); //t2就等待了。立即释放锁。将来醒过来的时候,是从这里醒过来的时候
 63                     } catch (InterruptedException e) {
 64                         e.printStackTrace();
 65                     }
 66                 }
 67                 
 68                 System.out.println(s.name + "---" + s.age);
 69                 //林青霞---27
 70                 //刘意---30
 71                 
 72                 //修改标记
 73                 s.flag = false;
 74                 //唤醒线程
 75                 s.notify(); //唤醒t1
 76             }
 77         }
 78     }
 79 }
 80 
 81 /*
 82  * 分析:
 83  *         资源类:Student    
 84  *         设置学生数据:SetThread(生产者)
 85  *         获取学生数据:GetThread(消费者)
 86  *         测试类:StudentDemo
 87  * 
 88  * 问题1:按照思路写代码,发现数据每次都是:null---0
 89  * 原因:我们在每个线程中都创建了新的资源,而我们要求的时候设置和获取线程的资源应该是同一个
 90  * 如何实现呢?
 91  *         在外界把这个数据创建出来,通过构造方法传递给其他的类。
 92  * 
 93  * 问题2:为了数据的效果好一些,我加入了循环和判断,给出不同的值,这个时候产生了新的问题
 94  *         A:同一个数据出现多次
 95  *         B:姓名和年龄不匹配
 96  * 原因:
 97  *         A:同一个数据出现多次
 98  *             CPU的一点点时间片的执行权,就足够你执行很多次。
 99  *         B:姓名和年龄不匹配
100  *             线程运行的随机性
101  * 线程安全问题:
102  *         A:是否是多线程环境        是
103  *         B:是否有共享数据        是
104  *         C:是否有多条语句操作共享数据    是
105  * 解决方案:
106  *         加锁。
107  *         注意:
108  *             A:不同种类的线程都要加锁。
109  *             B:不同种类的线程加的锁必须是同一把。
110  * 
111  * 问题3:虽然数据安全了,但是呢,一次一大片不好看,我就想依次的一次一个输出。
112  * 如何实现呢?
113  *         通过Java提供的等待唤醒机制解决。
114  * 
115  * 等待唤醒:
116  *         Object类中提供了三个方法:
117  *             wait():等待
118  *             notify():唤醒单个线程
119  *             notifyAll():唤醒所有线程
120  *         为什么这些方法不定义在Thread类中呢?
121  *             这些方法的调用必须通过锁对象调用,而我们刚才使用的锁对象是任意锁对象。
122  *             所以,这些方法必须定义在Object类中。
123  */
124 public class StudentDemo {
125     public static void main(String[] args) {
126         //创建资源
127         Student s = new Student();
128         
129         //设置和获取的类
130         SetThread st = new SetThread(s);
131         GetThread gt = new GetThread(s);
132 
133         //线程类
134         Thread t1 = new Thread(st);
135         Thread t2 = new Thread(gt);
136 
137         //启动线程
138         t1.start();
139         t2.start();
140     }
141 }

线程的状态转换图及常见执行情况:

技术分享图片 

多线程之Java中的等待唤醒机制

原文:https://www.cnblogs.com/ssh-html/p/10111489.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!