黑马程序员技术交流社区

标题: 卖票中同步锁的问题。 [打印本页]

作者: 张扬123    时间: 2012-8-5 04:18
标题: 卖票中同步锁的问题。
  1. /*
  2. 需求:简单的卖票程序。
  3. 多个窗口卖票。
  4. */

  5. class Ticket implements Runnable
  6. {
  7.         private int tick = 500;
  8.         Object obj = new Object();
  9.         public void run()
  10.         {
  11.                 while(true)
  12.                 {
  13.                         synchronized(obj)
  14.                         {
  15.                         if (tick>0)
  16.                         {
  17.                                 try
  18.                                 {
  19.                                         Thread.sleep(10);
  20.                                 }
  21.                                 catch (Exception e)
  22.                                 {
  23.                                 }
  24.                                 System.out.println(Thread.currentThread().getName()+"卖出:"+tick--);
  25.                         }
  26.                         }
  27.                 }
  28.         }
  29. }




  30. class  TicketDemo
  31. {
  32.         public static void main(String[] args)
  33.         {
  34.                 Ticket t = new Ticket();

  35.                 Thread t1 = new Thread(t);
  36.                 Thread t2 = new Thread(t);
  37.                 Thread t3 = new Thread(t);
  38.                 Thread t4 = new Thread(t);
  39.                 t1.start();
  40.                 t2.start();
  41.                 t3.start();
  42.                 t4.start();

  43.         }
  44. }
复制代码
今天复习的时候想到一个问题。以上是代码。synchronized相当于一个锁,毕老师讲的比喻是这里面相当于有一个1和0,代表真和假。假如1线程进来了之后把1改为0,然后sleep,此时其他的线程都进不来,sleep完之后,1线程会执行打印一次,然后把0改为1。这个我理解,可是很明显,1线程只打印一次以后就出去了,把假改为真之后,相当于4个线程又开始同时抢夺执行权往同步里面进。为什么运行结果却总是类似于:Thread-1卖出:98  Thread-1卖出:97 Thread-1卖出:96 Thread-1卖出:95 Thread-1卖出:94 Thread-1卖出:93 Thread-1卖出:92 。。。(很多遍)Thread-3卖出:88 Thread-3卖出:87 Thread-3卖出:86 Thread-3卖出:85 Thread-3卖出:84 Thread-3卖出:83。。。这样的呢?打印一次以后出去大家不是共同抢夺么?这样的结果岂不是相当于1线程打印了,然后出去了,然后他又抢到了。并且抢到很多次,这样的运行结果其中是不是还有其他的猫腻呢?我的意思大家明白了么。。。还有,我已经运行了很多遍很多遍了,结果都大致这样的。相信大家都已经睡了,谁早上看到了帮我解答一下吧。

作者: 杨锦    时间: 2012-8-5 08:46
本帖最后由 杨锦 于 2012-8-5 08:49 编辑

本来就这样啊,谁抢到都是随机的,抢到了执行几次也是随机的,你要想让他们一人只执行一次,就只能用多线程的通信了,哈哈哈哈,我回到你的帖了!!!

就是定义标记,然后wait(),notify(),那个。


jdk1.5之后,可以用await(),和signal()方法,可以指定唤醒哪一条线程
作者: 张振纲    时间: 2012-8-5 10:18
首先,当一线程释放执行权以后,本来就是四个线程同时在抢
而且他们是同一级别的,自然谁抢到都有可能

楼主可以借鉴一下优先级那块的内容
提高优先级也只是执行概率变高,并不是一直执行谁

作者: 张雪磊    时间: 2012-8-5 12:35
本帖最后由 张雪磊 于 2012-8-5 12:36 编辑

/*
需求:简单的卖票程序。
多个窗口卖票。
*/

class Ticket implements Runnable
{
        private int tick = 500;
        Object obj = new Object();
        public void run()
        {
                while(true)
                {
                        synchronized(obj)

                                /*
                                     你说的不错,假如有四个线程A,B,C,D来抢夺执行权,用毕老师的举例说就是锁的开关控制线程的进入,
                                    如果用1来表示锁开,0来表示锁关,  如果A抢到了,当他执行到 synchronized(obj) 后会判断一下锁,
                                    由于 这时候obj是1,也就是锁是开着的,说明里面没有别的线程,那A就可以进入执行里面的代码,当然
                                    在此之前,他会把obj从1改为0,这样即使他执行到下面的Thread.sleep(10); 其他线程也无法进入。当A重新
                                    获取执行权后,就继续往下执行,这样就保证了同步代码块里的程序被同步执行。当A执行完同步代码块
                                    出去后,又会把obj由0改为1这样其他线程由可以继续执行了。 当A执行完后,其他线程都有机会得到执行权,
                                    假如这个时候B抢到执行权,又会把obj由1改为0。然后执行完出来再把0改为1。对于为什么会一下一个线程
                                    打印一大片,这个是由CPU随机决定的,并不存在什么猫腻,这种情况,不同结果概率都有,可能你运行个
                                    成千上万遍才能看到一个结果,没必要太纠结这个。我运行就有一个线程就打了两个,就被其他线程抢走了的情况

                                    
                               */
                        {
                        if (tick>0)
                        {
                                try
                                {


                                        Thread.sleep(10);
                                }
                                catch (Exception e)
                                {
                                }
                                System.out.println(Thread.currentThread().getName()+"卖出:"+tick--);
                        }
                        }
                }
        }
}




class  TicketDemo
{
        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();

        }
}



作者: 张扬123    时间: 2012-8-6 08:16
杨锦 发表于 2012-8-5 08:46
本来就这样啊,谁抢到都是随机的,抢到了执行几次也是随机的,你要想让他们一人只执行一次,就只能用多线程 ...

抱歉回复这么晚,因为我的电脑坏了一天,啥事没干净弄电脑了。。。
作者: 张扬123    时间: 2012-8-6 08:16
张振纲 发表于 2012-8-5 10:18
首先,当一线程释放执行权以后,本来就是四个线程同时在抢
而且他们是同一级别的,自然谁抢到都有可能

结果就是一连串的。
作者: 张扬123    时间: 2012-8-6 08:17
问题已解决。电脑坏了,回复晚了。
作者: 王程    时间: 2012-8-6 08:37
我只能说,楼主,这个真的是随即的,不要想太多,我也尝试运行了一下,结果是

如果你想要线程轮流执行的话,还是用notify,和wait方法吧
作者: 杨锦    时间: 2012-8-6 08:39
张扬123 发表于 2012-8-6 08:16
抱歉回复这么晚,因为我的电脑坏了一天,啥事没干净弄电脑了。。。

...........抱什么歉啊,我也只能在教室才能上论坛,在宿舍论坛都上不去,不知道咋回事
作者: 张扬123    时间: 2012-8-7 03:09
杨锦 发表于 2012-8-6 08:39
...........抱什么歉啊,我也只能在教室才能上论坛,在宿舍论坛都上不去,不知道咋回事 ...

最近RMB紧张,等宽裕点了找你们去。




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