A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 邓超军 中级黑马   /  2012-7-24 17:14  /  2364 人查看  /  8 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

代码如下:
  1. public class JavaApp {
  2.        
  3.         public static void main(String... args)
  4.     {
  5.                 Ticket tc=new Ticket();
  6.                 Thread th1=new Thread(tc);
  7.                 Thread th2=new Thread(tc);
  8.                 Thread th3=new Thread(tc);
  9.                 Thread th4=new Thread(tc);
  10.                 th1.start();
  11.                 th2.start();
  12.                 th3.start();
  13.                 th4.start();
  14.     }
  15. }

  16. class Ticket implements Runnable
  17. {
  18.         private int num=400;
  19.         public void run()
  20.         {
  21.                 Object obj=new Object();
  22.                
  23.                 while(true)
  24.                 {  
  25.                         synchronized(obj)
  26.                     {
  27.                                 if(num>0)
  28.                                 {
  29.                                         try
  30.                                         {
  31.                                                 Thread.sleep(8);
  32.                                         }catch(Exception e){}
  33.                                         System.out.println(Thread.currentThread().getName()+"....sale : "+ num--);
  34.                                 }
  35.                         }
  36.                 }
  37.         }
  38. }
复制代码
运行结果出现了-1,-2,但把锁改成this就没有,这是为什么?这两种锁有什么区别?

评分

参与人数 1技术分 +1 收起 理由
韦念欣 + 1 赞一个!

查看全部评分

8 个回复

倒序浏览
public class JavaApp {

        
        public static void main(String... args)

    {

                Ticket tc=new Ticket();

                Thread th1=new Thread(tc);

                Thread th2=new Thread(tc);

                Thread th3=new Thread(tc);

                Thread th4=new Thread(tc);

                th1.start();

                th2.start();

                th3.start();

                th4.start();

    }

}

class Ticket implements Runnable

{

        private int num=400;

        public void run()

        {

                Object obj=new Object();//因为这里用的是两把锁,线程进来后每一个线程都创建了自己的
                                                   //Object对象,就好比一人一把锁,锁不唯一了。改成this的话就代表本类对象,本类对象是唯一的
                                                  //其实也可以把Object在run()方法外边创建这样也保证了锁的唯一

               
                while(true)

                {  

                        synchronized(obj)

                    {

                                if(num>0)

                                {

                                        try

                                        {

                                                Thread.sleep(8);

                                        }catch(Exception e){}

                                        System.out.println(Thread.currentThread().getName()+"....sale : "+ num--);

                                }

                        }

                }

        }

}
回复 使用道具 举报
原因就因为obj是方法里的一个局部变量每个线程间持有的都是不同对象的锁
假如A线程进入run方法,就会创建一个obj,A线程进入同步快后持有的就是刚才创建的obj的锁
B线程进入run方法,又会创建一个obj(这里把它叫做obj2),B线程进入同步快后持有的就是刚刚创建的obj2的锁
如果有C成成也是一样情况。。。。所以这些线程不能同步


回复 使用道具 举报
本帖最后由 曹俊 于 2012-7-24 18:05 编辑





楼主:在这个函数中你用了同步代码块这个方法来解决程序中的安全问题,同步代码块中的锁是任意的对象,所以你创建了Object obj = new obj();但你把这个对象放在了run()方法中,导致上面的th1、th2、th3、th4线程都会创建自己的锁,这时就产生了四把锁,没有起到同步的作用!
而你用this这个对象,指的就是我上面图中第22行的对象,这时这个对象是这四个线程共有的,四个线程使用这个对象就保证了同步代码块中一把锁的效果,能起到同步的作用。
解决办法:将你的Object obj = new Object();放在22行覆盖Ticket t = new Ticket();
或者像我上面为你准备的代码也可以解决,只是我上面的代码中Object obj = new Object();就是一段没用的代码了。
希望可以帮你解决问题哈!
有什么错误,欢迎指正~~~~~!{:soso__8961432591078930798_3:}

2.jpg (12.19 KB, 下载次数: 67)

2.jpg

1.jpg (59.34 KB, 下载次数: 88)

1.jpg
回复 使用道具 举报
曹俊 发表于 2012-7-24 18:03
楼主:在这个函数中你用了同步代码块这个方法来解决程序中的安全问题,同步代码块中的锁是任意的对象, ...

额...图发多了,不好意思啊。。。
回复 使用道具 举报
同步的好处:解决了线程的安全问题。
同步的前提:
1、同步中如果只有一个线程在执行。是没有必要同步的。
2、如果有多个线程需要同步,必须要保证它们使用的一个锁。这个前提的好处:如果在多线程中加入了同步后,还是出现了安全问题的话。这时就可以用这个前提来对程序进行分析。
public class JavaApp {

        

        public static void main(String... args)

    {

                Ticket tc=new Ticket();

                Thread th1=new Thread(tc);

                Thread th2=new Thread(tc);

                Thread th3=new Thread(tc);

                Thread th4=new Thread(tc);

                th1.start();

                th2.start();

                th3.start();

                th4.start();

    }

}



class Ticket implements Runnable

{

        private int num=400;

        public void run()

        {

                Object obj=new Object();//每开启一个线程就实例化一次,那么四个线程就用的四个锁,完全违背了同步的必要前提,所有的线程共用一把锁。

               

                while(true)

                {  

                        synchronized(obj)

                    {

                                if(num>0)

                                {

                                        try

                                        {

                                                Thread.sleep(8);

                                        }catch(Exception e){}

                                        System.out.println(Thread.currentThread().getName()+"....sale : "+ num--);

                                }

                        }

                }
所以用obj这个锁的话会出现安全问题,如出现-1,-2的情况。而用this这个本类对象引用的话,就符合同步的两个前提,就不会出现安全问题。
        }

}

回复 使用道具 举报
李菁 中级黑马 2012-7-24 20:16:42
7#
17.class Ticket implements Runnable

18.{

19.        private int num=400;

20.        public void run()

21.        {

22.                Object obj=new Object();   每个线程都实例化了,在run方法外边实例化就可以使线程唯一
                                                            用this就代表当前类的对象,是唯一的,线程就可以同步了

23.               

24.                while(true)

25.                {  

26.                        synchronized(obj)

27.                    {

28.                                if(num>0)

29.                                {

30.                                        try

31.                                        {

32.                                                Thread.sleep(8);

33.                                        }catch(Exception e){}

34.                                        System.out.println(Thread.currentThread().getName()+"....sale : "+ num--);

35.                                }

36.                        }

37.                }

38.        }

39.}
回复 使用道具 举报
黄锐 初级黑马 2012-7-24 21:17:19
8#
因为你把锁改成了this锁,这样同步的对象就指示为当前对象,调用这个方法的对象
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马