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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 夏儒日 中级黑马   /  2012-7-2 22:20  /  1977 人查看  /  7 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

一个关于多线程的安全问题.一个多窗口同时买票的程序.为什么用同步代码块解决多线程安全问题的时候,在创建Object对象的两个位置输出结果不一样呢?放在位置1能解决安全性问题,而在位置2创建Object对象不能解决安全性问题呢?代码如下,求各位大神指点迷津!谢谢~~~
class Ticket implements Runnable
{
        private static int tick=100;
        Object obj=new Object();//创建Object对象位置1
        public void run()
        {
                while(true)
                {
                        //Object obj=new Object();创建Object对象位置2
                        synchronized(obj)
                        {
                                if (tick>0)
                                {
                                        try
                                        {
                                                Thread.sleep(10);
                                                System.out.println(Thread.currentThread().getName()+"...sale.."+tick--);
                                        }
                                        catch (Exception e)
                                        {
                                                System.out.println("错误了!!");
                                        }
                                        System.out.println(Thread.currentThread().getName()+"...sale.."+tick--);
                                }
                        }
                }
        }
}
class TicketDemo2
{
        public static void main(String[] args)
        {
                Ticket t=new Ticket();
                Thread t1=new Thread(t);
                Thread t2=new Thread(t);
                Thread t3=new Thread(t);
                Thread t4=new Thread(t);
               
                t1.start();
                t2.start();
                t3.start();
                t4.start();
        }
}

7 个回复

倒序浏览
因为你是针对obj进行锁定  如果在1位置  整个类中只有一个obj  而在2位置   没调用一次 就会新建一个obj  每一个线程的obj都不一样  所以就不能锁定了
回复 使用道具 举报
这个问题 毕老师的视频讲的很清楚,不懂再看一遍吧
回复 使用道具 举报
刚才一着急忘了把try里面的打印语句删了,不过无伤大雅,主要问题还是创建对象的位置不同而导致的问题,想不明白,忘大神赐教.
回复 使用道具 举报
同步的关键在于,是否使用同一把锁,即同步的锁是同一个对象。你定义在循环里面,则每次都会新建一个Object对象,从而导致不是一把锁,当然实现不了同步了
回复 使用道具 举报
确定是否在一个同步内,关键在于是否是同一个锁,也就是synchronized()中传入的是否是同一个对象,如果obj定义在2的位置,那么每次开始循环都会建立一个新的obj,也就是说每次循环所用的锁都不是同一个。  现在有lock了为啥不要用lock呢。。。
回复 使用道具 举报
class Ticket implements Runnable
{
        private static int tick=100;
        Object obj=new Object();//创建Object对象位置1,成员变量,当创建对象后t后,对象中只有一个obj,也就是只有一把锁
        public void run()
        {
                while(true)
                {
                        //Object obj=new Object();创建Object对象位置2,此位置时,每次调用run方法都会重新new一个obj,也就是不是同一把锁,所以没有起到同步的作用。同步需要共享同一把锁的。
                        synchronized(obj)
                        {
                                if (tick>0)
                                {
                                        try
                                        {
                                                Thread.sleep(10);
                                                System.out.println(Thread.currentThread().getName()+"...sale.."+tick--);
                                        }
                                        catch (Exception e)
                                        {
                                                System.out.println("错误了!!");
                                        }
                                        System.out.println(Thread.currentThread().getName()+"...sale.."+tick--);
                                }
                        }
                }
        }
}
class TicketDemo2
{
        public static void main(String[] args)
        {
                Ticket t=new Ticket();
                Thread t1=new Thread(t);
                Thread t2=new Thread(t);
                Thread t3=new Thread(t);
                Thread t4=new Thread(t);
               
                t1.start();
                t2.start();
                t3.start();
                t4.start();
        }
}

评分

参与人数 1技术分 +1 收起 理由
黑马张扬 + 1 很给力!

查看全部评分

回复 使用道具 举报
柯玲 中级黑马 2012-7-13 10:11:34
8#
       在(1)位置处的obj是成员变量,是程序中的共享数据,同ticket一样,是堆内存中的共享数据。 在启动两个线程的时候,保证了是使用的同一个对象(锁),符合同步的前提:“多个线程使用同一个锁”,其实就可以把定义在此处的obj想象成ticket呀!

     因为run()是每个线程子类必须实现的方法,main()中通过Ticket t=new Ticket()创建了一个新线程, 而(2)位置处的obj处于run方法内,当线程运行起来以后,栈内存会给每个在运行的线程分配一个独立的内存空间,这样四个线程中就有四个obj。四个线程不是持有相同的锁,违反了“多个线程使用同一个锁”,(2)位置处就不能解决安全性问题了
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马