黑马程序员技术交流社区

标题: 等待唤醒机制 [打印本页]

作者: 横溢天使    时间: 2015-9-26 13:10
标题: 等待唤醒机制
  1. class InputOutputDemo
  2. {
  3.         public static void main(String[] args)
  4.         {
  5.                 Res r=new Res();
  6.                 Input i=new Input(r);
  7.                 Output o=new Output(r);
  8.                 Thread t=new Thread(i);
  9.                 Thread t1=new Thread(o);
  10.                 t.start();
  11.                 t1.start();
  12.         }
  13. }
  14. class Res
  15. {
  16.         String name;
  17.         String sex;
  18.         boolean flag;
  19. }
  20. class Input implements Runnable
  21. {
  22.         private Res r;
  23.         Input(Res r)
  24.         {
  25.                 this.r=r;
  26.         }
  27.         public void run()
  28.         {
  29.                 int x=0;
  30.                 while(true)
  31.                 {
  32.                         synchronized(r)
  33.                         {
  34.                                 if(!r.flag)
  35.                                         try{r.wait();}catch (Exception e){}
  36.                                 if(x==0)
  37.                                 {
  38.                                         r.name="Mike";
  39.                                         r.sex="man";
  40.                                 }
  41.                                 else
  42.                                 {
  43.                                         r.name="丽丽";
  44.                                         r.sex="女女";
  45.                                 }
  46.                                 x=(x+1)%2;
  47.                                 r.flag=false;
  48.                                 r.notify();

  49.                         }
  50.                 }
  51.         }
  52. }
  53. class Output implements Runnable
  54. {
  55.         private Res r;
  56.         Output(Res r)
  57.         {
  58.                 this.r=r;
  59.         }
  60.         public void run()
  61.         {
  62.                 while(true)
  63.                 {
  64.                         synchronized(r)
  65.                         {
  66.                                 if(!r.flag)
  67.                                         try{r.wait();}catch (Exception e){}
  68.                                 System.out.println(r.name+"*****"+r.sex);
  69.                                 r.flag=true;
  70.                                 r.notify();
  71.                         }
  72.                 }
  73.         }
  74. }
  75. 毕老师讲的flag这,我实在搞不懂。Input和Output里边的flag是一个吗?if(r.flag)是什么意思?是不是代表flag是true?可是我感觉默认的flag值是false啊!真心搞不懂,还请那位大神详细指点指点,我感激不尽
复制代码



作者: 筱小酥    时间: 2015-9-26 13:44
flag定义在成员位置,没有赋值,而boolean的默认值为false,所以flag是false,Input和Output都调用的是成员变量,另外!r.flag是取反,为true
作者: 筱小酥    时间: 2015-9-26 13:45
flag定义在成员位置,没有赋值,而boolean的默认值为false,所以flag是false,Input和Output都调用的是成员变量,另外!r.flag是取反,为true,如果我的回答对你有帮助,希望打赏几个黑马币,急需
作者: 横溢天使    时间: 2015-9-26 14:34
不好意思,我Input类里的if(r.flag),不是if(!r.flag),Output里边的是if(!r.flag),我上边打错了。。
我问的是Input类里的if(r.flag)。毕老师说if(r.flag)结果是true,我实在是想不明白,还请您详细解答下
作者: 15001162522    时间: 2015-9-26 17:21
1.主函数下只声明了一个Res r,并将其分别传给了i和o,也就是说intput和output的中flag是同一个对象
2.if(r.flag)表示判断,如果r.flag==true,则继续执行该if作用域内的代码;如果r.flag==false,则跳过该if作用域内的代码,继续执行后续代码。
3.r.flag的值是不确定的,可能为true可能为false,只有当其为true时,if{}内的代码才会执行
作者: 横溢天使    时间: 2015-9-26 18:05
15001162522 发表于 2015-9-26 17:21
1.主函数下只声明了一个Res r,并将其分别传给了i和o,也就是说intput和output的中flag是同一个对象
2.if(r. ...

为什么r.flag的值是不确定呢?flag默认值不是false吗?那自然r.flag的的值是false啊?就是这搞不懂
作者: a8336675    时间: 2015-9-27 00:42
楼主你还是要把问题描述清楚。看了几遍,代码倒是看明白了,却还没弄清楚你想问啥。。
作者: 瑞雪雄起    时间: 2015-9-27 02:35
你的这个程序有点问题,你的程序会进入阻塞,可能你复制代码时出现了问题,其实这题考的是线程之间的通讯,也就是wait和notify。flag默认是false
作者: 瑞雪雄起    时间: 2015-9-27 02:38
class InputOutputDemo
{
        public static void main(String[] args)
        {
                Res r=new Res();
                Input i=new Input(r);
                Output o=new Output(r);
                Thread t=new Thread(i);
                Thread t1=new Thread(o);
                t.start();
                t1.start();
        }
}
class Res
{
        String name;
        String sex;
        boolean flag;
}
class Input implements Runnable
{
        private Res r;
        Input(Res r)
        {
                this.r=r;
        }
        public void run()
        {
                int x=0;
                while(true)
                {
                        synchronized(r)
                        {
                                if(!r.flag)
                                        try{r.wait();}catch (Exception e){}
                                if(x==0)
                                {
                                        r.name="Mike";
                                        r.sex="man";
                                }
                                else
                                {
                                        r.name="丽丽";
                                        r.sex="女女";
                                }
                                x=(x+1)%2;
                                r.flag=false;
                                r.notify();

                        }
                }
        }
}
class Output implements Runnable
{
        private Res r;
        Output(Res r)
        {
                this.r=r;
        }
        public void run()
        {
                while(true)
                {
                        synchronized(r)
                        {
                                if(r.flag)
                                        try{r.wait();}catch (Exception e){}
                                System.out.println(r.name+"*****"+r.sex);
                                r.flag=true;
                                r.notify();
                        }
                }
        }
}
作者: 瑞雪雄起    时间: 2015-9-27 03:01
正确代码
class InputOutputDemo
{
       public static void main(String[] args)
       {
               Res r=new Res();
               Input i=new Input(r);
               Output o=new Output(r);
              Thread t=new Thread(i);
               Thread t1=new Thread(o);
               t.start();
               t1.start();
       }
}
class Res
{
       String name;
       String sex;
       boolean flag;
}
class Input implements Runnable
{
       private Res r;
       Input(Res r)
       {
               this.r=r;
       }
       public void run()
       {
               int x=0;
               while(true)
               {
                       synchronized(r)
                       {
                               if(r.flag)
                                       try{r.wait();}catch (Exception e){}
                               if(x==0)
                               {
                                       r.name="Mike";
                                       r.sex="man";
                               }
                               else
                               {
                                       r.name="丽丽";
                                       r.sex="女女";
                               }
                               x=(x+1)%2;
                               r.flag=true;
                               r.notify();

                       }
               }
       }
}
class Output implements Runnable
{
       private Res r;
       Output(Res r)
       {
               this.r=r;
       }
       public void run()
       {
               while(true)
               {
                       synchronized(r)
                       {
                               if(!r.flag)
                                       try{r.wait();}catch (Exception e){}
                                                                try {
                                                                        Thread.sleep(1000);
                                                                } catch (InterruptedException e) {
                                                                 
                                                                        e.printStackTrace();
                                                                }
                               System.out.println(r.name+"*****"+r.sex);
                               r.flag=false;
                               r.notify();
                       }
               }
       }
}
作者: 横溢天使    时间: 2015-9-27 08:30
瑞雪雄起 发表于 2015-9-27 03:01
正确代码
class InputOutputDemo
{
  1.   if(r.flag)
  2.                                        try{r.wait();}catch (Exception e){}
  3.                                if(x==0)
  4.                                {
  5.                                        r.name="Mike";
  6.                                        r.sex="man";
  7.                                }
  8.                                else
  9.                                {
  10.                                        r.name="丽丽";
  11.                                        r.sex="女女";
  12.                                }
  13.                                x=(x+1)%2;
  14.                                r.flag=true;
  15.                                r.notify();
  16. 这段代码您能给解释下不?不明白什么意思,主要是开头if(r.flag)这不懂
复制代码

作者: fmi110    时间: 2015-9-27 13:58
Input 里的 if(!r.flag)  和  Output里if(r.flag)
这两个语句是对同一个flag进行判断,所以不管r.flag是true或false,都能保证一个if()判断为true,从而函数可以运行
事实上因为flag默认是false,所以是一开始是Input的run()先执行,input的run()方法末尾将r.flag设为ture,所以下次循环进来时,Input里面if()判断为false,不执行,而此时Output的if()判断true,output执行,末尾有改变flag,使下次循环时时Input执行,如此反复下去的。。。

其实flag相当于一个开关,它的作用是控制Input 和 Output交替执行任务(线程间通讯),flag为ture时,Input执行动作,Oupt不执行;flag为false时,相反。
而为了保证一个执行完后轮到另一个执行,在执行代码的末尾,就会将flag的值改变,相当于通知对方,我完成了,你可以运行了
作者: polarfox17    时间: 2015-9-27 16:12
我也是新手,大概能明白你的问题在哪里,就是不知道能不能给你说明白
首先,你的问题应该是卡在这个唤醒机制的原理,也就是那个判断的原理,
我们从头来分析,这段代码运行的时候是随机运行的,有可能多存几次数据,在连续打印几个相同的数据,因为打印的就只有数据库里的那唯一一个数据,In是改变里面的数据,而out是打印里面的数据,在这个前提下,就必须要做到存一次,取一次,才能达到我们的目的
就是通过if判断flag来完成的,flag我们用文字来表示比较好理解,flag就假设他为数据库里有没有数据,true就是有,flase就是没有,flag初始化为false,假设是t1线程先运行,那么走out,会判断一下,发现(!flag)是真,即没有数据!于是t1开始wait,那就剩下t这个线程,走In这段代码,判断flag,发现没有数据,好,那就存进去数据,存完之后会把flag改为true,即表示已经有数据了,然后还顺手notify唤醒了刚才wait的out,但是唤醒了不一定就运行,也就是说,这个in还有可能在占有运行权,再走一遍,首先判断flag,发现是true,有数据了,不用存了,于是wait,这时候没有别的线程了,t1就开始了,判断flag,是真,有数据,于是打印,并把flag改成false,即表示数据已经取出了,没有数据了,然后再notify,把t线程再唤醒,。。。。。。。。大概就是这样的、、、不知道你能不能读得懂
作者: 瑞雪雄起    时间: 2015-9-27 21:09
横溢天使 发表于 2015-9-27 08:30

你把我的代码运行下,你就会发现打印的字符串交替运行,两个线程交替运行

作者: fcl13761179064    时间: 2015-9-27 21:11
还在学基础,但是以后我会给你解决的.
作者: 横溢天使    时间: 2015-9-27 22:53
15001162522 发表于 2015-9-26 17:21
1.主函数下只声明了一个Res r,并将其分别传给了i和o,也就是说intput和output的中flag是同一个对象
2.if(r. ...

谢谢,问题解决了
作者: 年强    时间: 2015-9-28 08:25
线程的同步问题。。。要充分考虑到申请资源和释放资源的问题。。。。因此要设置以各变量来控制。。。就叫做互斥信号量

作者: liudongcan    时间: 2015-10-1 19:10
是同一个flag,因为flag是有无数据的依据。创建Res类时,boolean flag;此时flag默认是false,name和sex都没赋值,没有数据。r.flag中的r是创建Input或Output时作为参数传进来的对象r。当第一次进入Input中时,成员变量name和sex都没数据。r.flag == false,但!r.flag == true,就为成员变量赋值了。赋值后就是有数据了,flag就要flag = true了,为何你的代码没这样?
作者: liudongcan    时间: 2015-10-1 19:14
liudongcan 发表于 2015-10-1 19:10
是同一个flag,因为flag是有无数据的依据。创建Res类时,boolean flag;此时flag默认是false,name和sex都 ...

你的代码有问题,没有数据都没赋值而是等待的
作者: 弗人    时间: 2015-10-6 18:20
不论是Input还是Output里的flag都引用的是r类中的flag,所以是一个。因为创建了r对象,所以会对flag进行初始化,而boolean类型的数据被初始化后的值为false,而if后的是(!r.flag这个值为true。
作者: LLLLL    时间: 2015-10-10 18:42
。。。。。。。。。。。。。。。。。。。。
作者: 朦胧色彩    时间: 2015-10-21 10:40
1、Input和Output里边的flag是一个吗?
答:是的,确实是同一个flag,因为两个线程都是操作同一个资源。

2、if(r.flag)是什么意思?
答:判断r.flag是不是true,是的话就可以进去if代码块里执行。

3、是不是代表flag是true?
答:代表的是是否输入了资源以及是否输出了资源,如果是false的话,说明还没有输入,所以wait,让output线程来输出,等到输出了,就让flag=true,并且output线程wait,把input唤醒(notify)来判断flag是不是true来进行输入资源。

4、可是我感觉默认的flag值是false啊!真心搞不懂,还请那位大神详细指点指点,我感激不尽
答:flag在同步代码块的最下面是变化的,不断在切换false和true。
作者: 涵門子弟    时间: 2015-11-1 21:47
都是大神,我听明白了,但是我是水贴的
作者: 子午鼬    时间: 2015-11-29 23:12
1.你的代码没编对,我复制粘贴了,运行不了。主要是你在Res这个类中没有对flag进行初始化。你把class中的flag=true,程序就可以运行了。2.你的代码的编写格式有问题,为了对齐请按tab键,不要打空格键,这样很不美观。下次注意。if(r.flag)是判断if中的值是真是假,是真就执行,假的化就跳过if语句执行。主要是你没有给flag进行初始化,不懂情有可原。最后祝你迎难而上,取得成功!




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