黑马程序员技术交流社区

标题: 毕老师第12天中的问题,同步 [打印本页]

作者: 李辉    时间: 2013-3-18 17:01
标题: 毕老师第12天中的问题,同步
本帖最后由 李辉 于 2013-3-23 07:20 编辑

毕老师在这个例子中开了两个线程,当我在毕老师的程序基础上又增加一个输出线程的时候,怎么保持两个输出线程的同步?我试了一下,在Output类中的run方法中增加一个同步是可以的,问题是为什么在Person中print方法中增加同步不可以?  代码如下:
class InputOutputDemo
{
        public static void main(String[] args)
        {
                Person per=new Person();
                new Thread(new Input(per)).start();
                new Thread(new Output(per)).start();
                new Thread(new Output(per)).start();
        }
}

class Person
{
        private String name;
        private String sex;
        boolean flag=false;
        public synchronized void set(String name,String sex)
        {
                if(flag)
                {
                        this.notifyAll();
                        try{this.wait();}catch(Exception e){System.out.println(e.toString());}
                }
                this.name=name;
                this.sex=sex;
                flag=true;
        }
        public synchronized void print()
        {
                //synchronized(Person.class)   //这里的同步为什么会导致死锁?
                //{
                        if(flag==false)
                        {
                                this.notifyAll();
                                try{this.wait();}catch(Exception e){System.out.println(e.toString());}
                        }
                        System.out.println(name+"....."+sex+Thread.currentThread());
                        flag=false;
                //}
        }
}

class Input implements Runnable
{
        Person p;
        public Input (Person p)
        {
                this.p=p;
        }
        public void run()
        {
                int flag=0;
                while(true)
                {
                        if(flag==0)
                        {
                                p.set("xiaowang","male");
                        }
                        else
                        {
                                p.set("xiaozhang","female");
                        }
                        flag=(flag+1)%2;
                }
        }
}


class Output implements Runnable
{
        Person p;
        public Output(Person p)
        {
                this.p=p;
        }
        public void run()
        {
                while(true)
                {
                        //synchronized(Output.class)     // 这里加上同步可以解决两个输出线程的问题
                        //{
                                p.print();
                        //}
                }
        }
}

作者: 陈腾跃_2013    时间: 2013-3-18 18:26
本帖最后由 陈腾跃_2013 于 2013-3-18 18:30 编辑

我也是菜鸟,解答不是很到位,坐等高手。

觉得有点多此一举,print方法上已经有同步了,再使用同步。
且print上的synchronized使用的锁是this,你在方法体上使用的锁是“Person.class”字节码文件,锁不同。
记得前面的视频有讲到,同步中嵌套同步,锁不同,会造成死锁。


这是我自己改后的代码,可以正常运行
  1. public void print() {
  2.                 synchronized (this) // 这里的同步为什么会导致死锁?
  3.                 {
  4.                         if (flag == false) {
  5.                                 try {
  6.                                         this.wait();
  7.                                         System.out.println(Thread.currentThread() + " wait");
  8.                                 } catch (Exception e) {
  9.                                         System.out.println(e.toString());
  10.                                 }
  11.                         }
  12.                 System.out.println(name + "....." + sex + Thread.currentThread());
  13.                 flag = false;
  14.                 this.notifyAll();
  15.                 }
  16.         }
复制代码
个人观点仅供参考。
代码不敢确定完全合适,望有人拍砖指导,谢谢。


作者: 张洪慊    时间: 2013-3-18 19:18
本帖最后由 张洪慊 于 2013-3-18 19:25 编辑

你这个够绕,我分析的加上出现的问题:
加上点代码,看它是怎么执行的:
  1. class Person
  2. {
  3.         private String name;
  4.         private String sex;
  5.         boolean flag=false;
  6.         public synchronized void set(String name,String sex)
  7.         {
  8.    // System.out.println(Thread.currentThread().getName()+"①---"+flag);
  9.                 if(flag)
  10.                 {     
  11. // System.out.println(Thread.currentThread().getName()+"②---"+flag);
  12.                         this.notify();
  13.    //System.out.println(Thread.currentThread().getName()+"notify---"+flag);
  14.                         try{this.wait();}catch(Exception e){System.out.println(e.toString());}
  15.                 }
  16.                 this.name=name;
  17.                 this.sex=sex;
  18.   //  System.out.println(Thread.currentThread().getName()+"③---"+flag);
  19.                 flag=true;
  20.   //System.out.println(Thread.currentThread().getName()+"④---"+flag);
  21.         }
  22.         public synchronized void print()
  23.         {

  24. //System.out.println(Thread.currentThread().getName()+"⑤---"+flag);
  25.                 synchronized(Person.class)   //这里的同步为什么会导致死锁?
  26.                 {
  27.                         if(flag==false)
  28.                         {
  29. //System.out.println(Thread.currentThread().getName()+"⑥---"+flag);
  30.                                 this.notify();
  31.    //   System.out.println(Thread.currentThread().getName()+"notify"+flag);
  32.                                 try{this.wait();}catch(Exception e){System.out.println(e.toString());}
  33.                         }
  34.                         System.out.println(name+"....."+sex+Thread.currentThread().getName());
  35.                         flag=false;
  36. //System.out.println(Thread.currentThread().getName()+"⑦---"+flag);
  37.    }
  38.   }
复制代码

分析下:
1.cpu切换到Thread-1->其中一个输出线程->flag=false->notify(此时没有等待线程)->Thread-1 等待
2.cpu切换到Thread-0->输入线程->flag=false->赋值->执行完set
3.cpu切换到Thread-2->无法进入同步代码块->因为Thread-1等待,该线程依然在同步代码块中->持有Person.class锁
4.cpu切换到Thread-0->此时Thread-0无法执行set->因为Thread-2在同步函数里面,依然持有this锁
以上 卡死- -.
作者: HM周磊    时间: 2013-3-18 20:33
楼上的大神,膜拜
作者: 李辉    时间: 2013-3-23 07:18
本帖最后由 李辉 于 2013-3-23 07:20 编辑

非常感谢各位的热心,学完了毕老师的线程的视频,我觉得这里完全没有必要用嵌套的同步,嵌套了就比较绕,关于嵌套的同步还是以后再思考吧,先学基础的。




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