黑马程序员技术交流社区

标题: 【记录】代码练习-等待唤醒机制 [打印本页]

作者: Kevin.Kang    时间: 2015-8-5 15:28
标题: 【记录】代码练习-等待唤醒机制
本帖最后由 Kevin.Kang 于 2015-8-5 15:32 编辑

如果是生产多个,和消费多个的话,两个线程需要加上同一把锁才行。
    但是这样做依然还存在着问题:
            1.如果消费者先抢到CPU执行权,消费数据,这时数据如果是空,就没有意义。
                应该等着数据生产出来,再去消费,这样才具有意义。
            2.如果生产者先抢到CPU执行权,生产数据,但是生产完一定数量的数据以后,还继续持有执行权,
                它还会继续生产数据,这还现实情况不符,需要等着消费者把数据消费以后,再生产。
   
    正常思路:
            1.生产者
                    先看是否有数据,有就等待,没有就生产,生产完通知消费者消费
            2.消费者
                    先看是否有数据,有就消费,没有就等待,消费完通知生产者生产
                    
java提供了一个等待唤醒机制来解决这个问题。




等待唤醒.png (9.1 KB, 下载次数: 1)

等待唤醒.png

作者: Kevin.Kang    时间: 2015-8-5 16:22
* 等待唤醒:
*         Object类中提供了三个方法:
*                 wait():等待
*                 notify():唤醒单个线程
*                 notifyAll():唤醒多个线程
*         为什么等待唤醒方法定义在Object类中:
*                 这些方法都是通过锁对象进行调用的,锁对象可以是任意的
*                 所以,这些方法必须定义在Object类中。
测试类:
  1. package com.kxg_03;
  2. public class StudentDemo {
  3.         public static void main(String[] args) {
  4.                 // 创建资源
  5.                 Student s = new Student();

  6.                 // 创建SetThread和GetThread对象
  7.                 SetThread st = new SetThread(s);
  8.                 GetThread gt = new GetThread(s);

  9.                 // 创建线程
  10.                 Thread t1 = new Thread(st);
  11.                 Thread t2 = new Thread(gt);

  12.                 // 开启线程
  13.                 t1.start();
  14.                 t2.start();
  15.         }
  16. }
复制代码
资源类:
  1. package com.kxg_03;
  2. /*
  3. * 定义学生类
  4. */
  5. public class Student {
  6.         String name;
  7.         int age;
  8.         boolean flag;// 用来判断是否存在资源,默认是flash,没有资源
  9. }
复制代码
生产者类:
  1. package com.kxg_03;

  2. /*
  3. * 设置学生信息的线程
  4. */
  5. public class SetThread implements Runnable {

  6.         private Student s;
  7.         private int i;

  8.         public SetThread(Student s) {
  9.                 this.s = s;
  10.         }
  11.         @Override
  12.         public void run() {
  13.                 while (true) {
  14.                         // 设置同步锁
  15.                         synchronized (s) {
  16.                                 // 如果有数据,生产者等待
  17.                                 if (!s.flag) {
  18.                                         try {
  19.                                                 s.wait();
  20.                                         } catch (InterruptedException e) {
  21.                                                 e.printStackTrace();
  22.                                         }
  23.                                 }

  24.                                 if (i % 2 == 0) {
  25.                                         s.name = "小明";
  26.                                         s.age = 5;
  27.                                 } else {
  28.                                         s.name = "汪汪";
  29.                                         s.age = 2;
  30.                                 }
  31.                                 i++;
  32.                                 // 生产完成,把变量改为有数据
  33.                                 s.flag = false;
  34.                                 // 唤醒线程
  35.                                 s.notify();
  36.                         }
  37.                 }
  38.         }
  39. }
复制代码
消费者类:
  1. package com.kxg_03;

  2. /*
  3. * 设置获取学生信息的线程
  4. */
  5. public class GetThread implements Runnable {

  6.         private Student s;

  7.         public GetThread(Student s) {
  8.                 this.s = s;
  9.         }
  10.         @Override
  11.         public void run() {
  12.                 while (true) {
  13.                         // 设置同步锁
  14.                         synchronized (s) {
  15.                                 // 如果没有数据,消费者就等待
  16.                                 if (s.flag) {
  17.                                         try {
  18.                                                 s.wait();
  19.                                         } catch (InterruptedException e) {
  20.                                                 e.printStackTrace();
  21.                                         }
  22.                                 }
  23.                                 System.out.println(s.name + ":" + s.age);
  24.                                 // 修改标记
  25.                                 s.flag = true;
  26.                                 // 唤醒线程
  27.                                 s.notify();
  28.                         }
  29.                 }
  30.         }
  31. }
复制代码









欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2