黑马程序员技术交流社区

标题: 关于毕老师145视频提出的疑问 [打印本页]

作者: 二货哈士奇    时间: 2014-10-30 16:13
标题: 关于毕老师145视频提出的疑问
本帖最后由 二货哈士奇 于 2014-10-30 16:18 编辑

/*
需求:完成线程间通信,避免出现错误信息,重复信息
思路:
1、定义一个资源类,作为多线程操作的对象
2、定义两个多线程来操作上述资源
3、通过持有相同锁的同步函数同步两个多线程,避免错误信息,保证数据安全性
4、通过等待唤醒机制,避免重复信息

步骤:
1、定义资源类 Res 作为被操作的对象,并建立对象r
2、定义两个类 In、Out implements Runnable,分别复写run函数
        建立两个Thread对象多线程进行In Out类
3、分别在In Out中定义两个同步函数,锁都定义为 资源对象r,保证同步数据安全性
4、分别在In Out中加入wait(),notify()函数,避免数据重复
*/

/*
对应视频145,线程间通信安全性,简化代码
这个代码与老师的区别在于setData,printData的函数中,if判断语句的else语句我加了括号,结果打印就是女女男男
测试后发现,printData的else函数加括号无影响,只要setData函数一加括号就打印异常
*/

class Res
{
        private String name;
        private String sex;
        private boolean flag=false;

        public synchronized void setData(String name,String sex)
        {
                if(this.flag)
                        try{this.wait();} catch(Exception e){}
        //        else
        //        {
                        this.name = name;
                        this.sex = sex;
                        flag = true;
                        this.notify();
        //        }
        }

        public synchronized void printData()
        {
                if(!flag)
                {
                        try{this.wait();} catch(Exception e){}
                }
                else
                {
                        System.out.println(this.name+"....."+this.sex);
                        flag = false;
                        this.notify();

                }
        }
}

class InPut implements Runnable
{       
        private Res r;
        InPut(Res r)
        {
                this.r =r;
        }

        public void run()
        {
                int x = 0;
                while(true)
                {
                        if(x==0)
                                r.setData("zhangsan","man");
                        else
                                r.setData("妹妹","女女女女女");
                        x = (x+1)%2;
                }
        }
}

class OutPut implements Runnable
{
        private Res r;
        OutPut(Res r)
        {
                this.r = r;
        }
        public void run()
        {
                while(true)
                        r.printData();
        }
}
class YiChangs
{
        public static void main(String[] args)
        {
                Res r = new Res();
                new Thread(new InPut(r)).start();
                new Thread(new OutPut(r)).start();
        }
}
如题,我是按照毕老师的视频写的代码
问题出现在第33行,毕老师当时的逻辑是当if不满足的时候,再执行name等属性的变更
所以我在第33行中加入了else,再做name属性的变更,而我的运行结果就和老师的不同时 女女男男 这样的格式
而不是老师所说的 女男女男 这个样子,出现了多线程安全问题
请帮忙分析下问题所在,多线程在进入wait之后,读到notify之后在哪里回复进行呢

作者: wzg1015    时间: 2014-10-30 16:13
本帖最后由 wzg1015 于 2014-10-30 21:34 编辑

你的逻辑错了,if不满足的时候,再执行name等属性的变更
说的是if不满足就会跳过等待环节直接执行下面的。如果满足,只是在等待,下次获取了执行权还是会执行下面的代码。
而你写了else,则是不满足才执行下面的,满足的话下次执行是不会执行else里面的语句的。
也就是那个if语句只要控制wait的执行,而后面的执不执行跟他是没关系的。你加上 了else,有了关系,所以导致不一样

作者: 二货哈士奇    时间: 2014-10-30 23:55
wzg1015 发表于 2014-10-30 21:32
你的逻辑错了,if不满足的时候,再执行name等属性的变更
说的是if不满足就会跳过等待环节直接执行下面的。 ...

逻辑没问题啊,
if不满足,说明条件变更了,需要执行name进行赋值,赋值后,进入循环再判断一次if,此时if将满足条件,进入wait等待。
if满足了,说明条件没有变更,进入等待,不需要执行那么变更语句。等到线程被唤醒了,直接在进行一次判断啊。
你说的“不满足执行,满足下次不执行”这个不可能吧,那个线程是个死循环,满足条件之后会在重新去读if判断,这时候唤醒后if是不满足的,会会自动执行下面的语句啊
作者: wzg1015    时间: 2014-10-31 00:24
二货哈士奇 发表于 2014-10-30 23:55
逻辑没问题啊,
if不满足,说明条件变更了,需要执行name进行赋值,赋值后,进入循环再判断一次if,此时i ...

怎么没问题,如果加了else下面的代码在if满足的条件下必定不运行。而不加else,则无论你if条件是否满足,下面的代码必定运行。
线程被唤醒了是继续往下执行的执行完成了以后才会进行第二次判断if
作者: 二货哈士奇    时间: 2014-10-31 08:32
wzg1015 发表于 2014-10-31 00:24
怎么没问题,如果加了else下面的代码在if满足的条件下必定不运行。而不加else,则无论你if条件是否满足, ...

哦哦 看到了,是每次调用InPut中的run方法时,x出现的问题,现在已经解决了,多谢兄弟了




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