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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 2528870651 高级黑马   /  2014-4-3 09:05  /  1702 人查看  /  20 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 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. */



复制代码

20 个回复

正序浏览
Engle 发表于 2014-4-3 11:58
多线程同步问题:   
    在多线程环境中,可能会有两个甚至更多的线程试图同时
访问一个有限的资源。必须 ...

哥们 你看错了吧 ! 我没有问怎么解决啊 ! 怎么解决我知道的
就是在分析没加锁的时候不知道为什么会出现这样的情况而已。。。。
回复 使用道具 举报
第一个窗口卖出第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


总之还是线程不同步引起的问题
回复 使用道具 举报
                                 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
回复 使用道具 举报
多线程同步问题:   
    在多线程环境中,可能会有两个甚至更多的线程试图同时
访问一个有限的资源。必须对这种潜在资源冲突进行预防。  
    解决方法:在线程使用一个资源时为其加锁即可。访问资
源的第一个线程为其加上锁以后,其他线程便不能再使用
那个资源,除非被解锁。
代码加上锁就可以了:
   synchronized {
         System.out.println(Thread.currentThread().getName()+"卖出第"+(ticket--)+"张门票。。。"+ticket);
回复 使用道具 举报
osully 发表于 2014-4-3 11:42
我做事为什么要等你做完????

一直以为是要等“;”结束才可以的 。原来不是啊 !  谢谢
回复 使用道具 举报
我做事为什么要等你做完????
回复 使用道具 举报
osully 发表于 2014-4-3 11:25
不同步,也就是说
线程1刚拿到ticket 还没来得及-- 就失去了cpu执行权
线程2就拿到了ticket ,所以就出现了 ...

也就是说在一句话还没有执行完的情况下,就被另一个线程抢到了???
不是要执行到“;”结束后才可以抢吗???
回复 使用道具 举报
不同步,也就是说
线程1刚拿到ticket 还没来得及-- 就失去了cpu执行权
线程2就拿到了ticket ,所以就出现了卖同一张票 , 后面一个ticket同理
回复 使用道具 举报
闲人 发表于 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


这是调换以后的结果
回复 使用道具 举报
闲人 发表于 2014-4-3 10:29
程序是从前到后执行的,你ticket--执行完以后,就把ticket--赋值给了ticket,当然ticket就会和ticket--是 ...

ticket-- 是执行后减1 ,后面的ticket就是ticket-1后的值,但是前面的ticket--打印的却不是-1后的值,而是打印ticket的值以后再减的1
回复 使用道具 举报
我知道加锁可以解决,我本来加了锁的,去了锁才发现了这个问题,关键是我不知道这是什么原因啊???我想知道具体是怎么造成这样的。
回复 使用道具 举报
2528870651 发表于 2014-4-3 10:24
不好意思后面的内容没有复制上,我不是问没有加锁会有什么问题,而是想问为什么前后2个ticket会相同, 前 ...

还是不同步导致了使用的两个ticket不一样
回复 使用道具 举报
本帖最后由 闲人 于 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 09:22
  • if (ticket>0)
  • System.out.println(Thread.currentThread().getName()+"卖出第"+(ticket--)+"张门 ...

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

    不好意思后面的内容没有复制上,我不是问没有加锁会有什么问题,而是想问为什么前后2个ticket会相同, 前面的ticket--了啊 ,后面的ticket应该是-1的啊
    回复 使用道具 举报
    osully 发表于 2014-4-3 09:15
    你又没加锁 当然了...
    这就是多线程操作同一资源 出现的安全问题
    你别说2个一样 5个6个一样都可能出现 ...

    不好意思后面的内容没有复制上,我不是问没有加锁会有什么问题,而是想问为什么前后2个ticket会相同, 前面的ticket--了啊 ,后面的ticket应该是-1的啊
    回复 使用道具 举报
    多个线程分享同一个资源的时候要加锁否则会出现像你这样的安全问题 加上同步锁 就ok了
    回复 使用道具 举报

    • if (ticket>0)
    • System.out.println(Thread.currentThread().getName()+"卖出第"+(ticket--)+"张门票。。。"+ticket);

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

    回复 使用道具 举报
    本帖最后由 闲人 于 2014-4-3 09:23 编辑

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

    都是概率问题,当你没有任何限制条件时,那么系统线程就会无限的抢夺的进程资源,然后你看到的情况就会出现。
    当然,你再次运行,也会出现不同的结果,看完毕老师线程锁的视频,这个问题就解决了
    回复 使用道具 举报
    12下一页
    您需要登录后才可以回帖 登录 | 加入黑马