黑马程序员技术交流社区

标题: 同步问题 [打印本页]

作者: 2528870651    时间: 2014-4-3 09:05
标题: 同步问题
本帖最后由 2528870651 于 2014-4-4 18:46 编辑
  1. <div class="blockcode"><blockquote>class  Ticket implements Runnable
  2. {
  3.         Object obj = new Object();
  4.         private int ticket=20;
  5.         public Ticket()
  6.         {
  7.                
  8.         }
  9.         public void run()
  10.         {
  11.                 while (ticket>0)
  12.                 {
  13.                         try
  14.                         {
  15.                                 Thread.sleep(100);
  16.                         }
  17.                         catch (InterruptedException e)
  18.                         {
  19.                                 e.printStackTrace();
  20.                         }
  21.                         
  22.                                 if (ticket>0)
  23.                                         System.out.println(Thread.currentThread().getName()+"卖出第"+(ticket--)+"张门票。。。"+ticket);
  24.                 //搞不懂为什么会出现2张相同的票,所以实验一下,可是后面的ticket怎么和(ticket--)相同呢?
  25.                 //按照我的理解ticket-- 应该在执行到(ticket-- )的后面就减1了,可是下面的结果在打印
  26.                 //2张相同票的时候,后面打印的ticket没有减1。为什么呢?
  27.                 //另外分析一下2张相同票是怎么出现的。
  28.                 //我不是问没有加锁会有什么问题,而是想问为什么前后2个ticket会相同, 前面的ticket--了啊 ,后面的ticket应该是-1的啊
  29.                 }
  30.         }
  31. }

  32. public class TicketDemo
  33. {
  34.         public static void main(String[] args)
  35.         {
  36.                 Ticket window = new Ticket();
  37.                 Thread t1 = new Thread(window, "第一个窗口");
  38.                 Thread t2 = new Thread(window, "第二个窗口");
  39.                 t1.start();
  40.                 t2.start();

  41.         }
  42. }
  43. /*

  44. 其中一个结果是:

  45. 第一个窗口卖出第19张门票。。。18   //就是这里,为什么第19,20张票后面打印的都是18呢
  46. 第二个窗口卖出第20张门票。。。18
  47. 第一个窗口卖出第18张门票。。。17
  48. 第二个窗口卖出第17张门票。。。16
  49. 第二个窗口卖出第16张门票。。。15
  50. 第一个窗口卖出第15张门票。。。14
  51. 第一个窗口卖出第14张门票。。。12
  52. 第二个窗口卖出第13张门票。。。12
  53. 第二个窗口卖出第12张门票。。。10
  54. 第一个窗口卖出第11张门票。。。10
  55. 第二个窗口卖出第10张门票。。。9
  56. 第一个窗口卖出第9张门票。。。8
  57. 第一个窗口卖出第8张门票。。。7    //这里2张相同票后面打印的都是7
  58. 第二个窗口卖出第8张门票。。。7
  59. 第二个窗口卖出第6张门票。。。5
  60. 第一个窗口卖出第7张门票。。。5
  61. 第二个窗口卖出第4张门票。。。3
  62. 第一个窗口卖出第5张门票。。。3
  63. 第二个窗口卖出第3张门票。。。2
  64. 第一个窗口卖出第3张门票。。。2
  65. 第一个窗口卖出第2张门票。。。0
  66. 第二个窗口卖出第1张门票。。。0
  67. */



复制代码


作者: osully    时间: 2014-4-3 09:15
你又没加锁 当然了...
这就是多线程操作同一资源 出现的安全问题
你别说2个一样 5个6个一样都可能出现
作者: 闲人    时间: 2014-4-3 09:20
本帖最后由 闲人 于 2014-4-3 09:23 编辑

因为没有加锁,所以多线程同步的时候,
               当两个线程同时进去,读取到不同的ticket然后输出,分别输出以后,剩余值就会出现第一种情况,同时打印同一个剩余的值;
               当两个线程同时进去,读取到相同ticket时,那么就会出现第二种情况他俩的输出结果也是相同的。

都是概率问题,当你没有任何限制条件时,那么系统线程就会无限的抢夺的进程资源,然后你看到的情况就会出现。
当然,你再次运行,也会出现不同的结果,看完毕老师线程锁的视频,这个问题就解决了

作者: H-Deka    时间: 2014-4-3 09:22


这两句代码用同步代码块
synchronized {
          if (ticket>0)
         System.out.println(Thread.currentThread().getName()+"卖出第"+(ticket--)+"张门票。。。"+ticket);


作者: lazy_xia    时间: 2014-4-3 09:25
多个线程分享同一个资源的时候要加锁否则会出现像你这样的安全问题 加上同步锁 就ok了
作者: 2528870651    时间: 2014-4-3 10:24
osully 发表于 2014-4-3 09:15
你又没加锁 当然了...
这就是多线程操作同一资源 出现的安全问题
你别说2个一样 5个6个一样都可能出现 ...

不好意思后面的内容没有复制上,我不是问没有加锁会有什么问题,而是想问为什么前后2个ticket会相同, 前面的ticket--了啊 ,后面的ticket应该是-1的啊
作者: 2528870651    时间: 2014-4-3 10:26
闲人 发表于 2014-4-3 09:20
因为没有加锁,所以多线程同步的时候,
               当两个线程同时进去,读取到不同的ticket然后输出, ...

不好意思后面的内容没有复制上,我不是问没有加锁会有什么问题,而是想问为什么前后2个ticket会相同, 前面的ticket--了啊 ,后面的ticket应该是-1的啊
作者: 2528870651    时间: 2014-4-3 10:28
H-Deka 发表于 2014-4-3 09:22
  • if (ticket>0)
  • System.out.println(Thread.currentThread().getName()+"卖出第"+(ticket--)+"张门 ...

  • 不好意思后面的内容没有复制上,我不是问没有加锁会有什么问题,而是想问为什么前后2个ticket会相同, 前面的ticket--了啊 ,后面的ticket应该是-1的啊
    作者: 闲人    时间: 2014-4-3 10:29
    本帖最后由 闲人 于 2014-4-3 10:31 编辑
    2528870651 发表于 2014-4-3 10:26
    不好意思后面的内容没有复制上,我不是问没有加锁会有什么问题,而是想问为什么前后2个ticket会相同, 前 ...

    程序是从前到后执行的,你ticket--执行完以后,就把ticket--赋值给了ticket,当然ticket就会和ticket--是同一个值了,你把你程序中的ticket--和ticket反过来试试,应该会得到你想要的结果

    作者: H-Deka    时间: 2014-4-3 10:33
    2528870651 发表于 2014-4-3 10:24
    不好意思后面的内容没有复制上,我不是问没有加锁会有什么问题,而是想问为什么前后2个ticket会相同, 前 ...

    还是不同步导致了使用的两个ticket不一样
    作者: 2528870651    时间: 2014-4-3 10:40
    我知道加锁可以解决,我本来加了锁的,去了锁才发现了这个问题,关键是我不知道这是什么原因啊???我想知道具体是怎么造成这样的。

    作者: 2528870651    时间: 2014-4-3 10:45
    闲人 发表于 2014-4-3 10:29
    程序是从前到后执行的,你ticket--执行完以后,就把ticket--赋值给了ticket,当然ticket就会和ticket--是 ...

    ticket-- 是执行后减1 ,后面的ticket就是ticket-1后的值,但是前面的ticket--打印的却不是-1后的值,而是打印ticket的值以后再减的1
    作者: 2528870651    时间: 2014-4-3 10:49
    闲人 发表于 2014-4-3 10:29
    程序是从前到后执行的,你ticket--执行完以后,就把ticket--赋值给了ticket,当然ticket就会和ticket--是 ...

    试试看再说 ,不管怎样 谢谢了:)


    第二个窗口卖出第20张门票。。。20
    第一个窗口卖出第20张门票。。。19
    第二个窗口卖出第18张门票。。。18
    第一个窗口卖出第17张门票。。。17
    第二个窗口卖出第16张门票。。。16
    第一个窗口卖出第15张门票。。。15
    第二个窗口卖出第14张门票。。。14
    第一个窗口卖出第13张门票。。。13
    第二个窗口卖出第12张门票。。。12
    第一个窗口卖出第11张门票。。。11
    第二个窗口卖出第10张门票。。。10
    第一个窗口卖出第9张门票。。。9
    第二个窗口卖出第8张门票。。。8
    第一个窗口卖出第7张门票。。。7
    第二个窗口卖出第6张门票。。。6
    第一个窗口卖出第5张门票。。。5
    第二个窗口卖出第4张门票。。。4
    第一个窗口卖出第3张门票。。。3
    第二个窗口卖出第2张门票。。。2
    第一个窗口卖出第1张门票。。。1


    这是调换以后的结果
    作者: osully    时间: 2014-4-3 11:25
    不同步,也就是说
    线程1刚拿到ticket 还没来得及-- 就失去了cpu执行权
    线程2就拿到了ticket ,所以就出现了卖同一张票 , 后面一个ticket同理
    作者: 2528870651    时间: 2014-4-3 11:32
    osully 发表于 2014-4-3 11:25
    不同步,也就是说
    线程1刚拿到ticket 还没来得及-- 就失去了cpu执行权
    线程2就拿到了ticket ,所以就出现了 ...

    也就是说在一句话还没有执行完的情况下,就被另一个线程抢到了???
    不是要执行到“;”结束后才可以抢吗???
    作者: osully    时间: 2014-4-3 11:42
    我做事为什么要等你做完????
    作者: 2528870651    时间: 2014-4-3 11:44
    osully 发表于 2014-4-3 11:42
    我做事为什么要等你做完????

    一直以为是要等“;”结束才可以的 。原来不是啊 !  谢谢
    作者: Engle    时间: 2014-4-3 11:58
    多线程同步问题:   
        在多线程环境中,可能会有两个甚至更多的线程试图同时
    访问一个有限的资源。必须对这种潜在资源冲突进行预防。  
        解决方法:在线程使用一个资源时为其加锁即可。访问资
    源的第一个线程为其加上锁以后,其他线程便不能再使用
    那个资源,除非被解锁。
    代码加上锁就可以了:
       synchronized {
             System.out.println(Thread.currentThread().getName()+"卖出第"+(ticket--)+"张门票。。。"+ticket);

    作者: 请备注    时间: 2014-4-3 12:29
                                     if (ticket>0)
                                            System.out.println(Thread.currentThread().getName()+"卖出第"+(ticket--)+"张门票。。。"+ticket);

    当ticket>0时 (假设ticket=18)  线程1 进来了正准备卖18号票,并自减 。可是这个时候
                                                  线程2抢到执行权跑进来了(输出语句没来的及执行,末自减)。
                                                 这时又要判断if条件
    ticket>0  ,这时 ticket还是等于18,于是 2 个线程都执行了输出语句,ticket的值都 是18

    作者: 年轻的老头    时间: 2014-4-3 12:32
    第一个窗口卖出第8张门票。。。7    //这里2张相同票后面打印的都是7
    第二个窗口卖出第8张门票。。。7

    thread1
    StringBuilder1=“第一个窗口卖出第8张门票”

    thread2
    StringBuilder2=“第二个窗口卖出第8张门票” ticket从变量区载入堆栈区(此时等于8)

    thread1
    ticket从变量区载入堆栈区 ticket--
    StringBuilder1+=“张门票。。。7”

    thread2
    ticket--此时不用再载入堆栈区(此时等于8)
    第二个窗口卖出第8张门票。。。7
    StringBuilder2+=“张门票。。。7”

    ticket--:
    iload_1      
    iinc          1, -1


    总之还是线程不同步引起的问题
    作者: 2528870651    时间: 2014-4-3 13:25
    Engle 发表于 2014-4-3 11:58
    多线程同步问题:   
        在多线程环境中,可能会有两个甚至更多的线程试图同时
    访问一个有限的资源。必须 ...

    哥们 你看错了吧 ! 我没有问怎么解决啊 ! 怎么解决我知道的
    就是在分析没加锁的时候不知道为什么会出现这样的情况而已。。。。




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