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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 尘埃落定 中级黑马   /  2014-7-28 09:07  /  1626 人查看  /  11 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

各位大侠,帮忙看看下面代码同步没有成功的原因,看视频上就是这么写的,怎么自己写的就问题一堆呢?{:3_65:}
  1. class SaleTicket2 extends Thread
  2. {
  3.         Object obj = new Object();
  4.         private static int tick = 100;
  5.         public void run()
  6.         {
  7.                 while(true)
  8.                 {        System.out.println("tick="+tick);
  9.                         synchronized(obj)
  10.                         {
  11.                                 if (tick > 0)
  12.                                 {
  13.                                         try{sleep(10);}catch(Exception e){}
  14.                                         System.out.println(currentThread().getName()+"---sale----+"+tick--);//同步过了,怎么还有0,-1和-2?
  15.                                 }
  16.                         }
  17.                 }
  18.         }
  19. }

  20. class ThreadLockTest
  21. {
  22.         public static void main(String[] args)
  23.         {
  24.                 SaleTicket2 st21 = new SaleTicket2();
  25.                 SaleTicket2 st22 = new SaleTicket2();
  26.                 SaleTicket2 st23 = new SaleTicket2();
  27.                 SaleTicket2 st24 = new SaleTicket2();
  28.                 st21.start();
  29.                 st22.start();
  30.                 st23.start();
  31.                 st24.start();

  32.         }
  33. }
复制代码


11 个回复

倒序浏览
问题出在你13行代码上,当一个线程卖出最后一张票后,其它三个处于睡眠状态的线程重新获取cpu执行权时,就会卖出0,-1,-2号票了。
回复 使用道具 举报
楼主,你把if变成while试试,13行线程睡眠之后,由于if只会判断一次,那么之前进来的线程就不会去判断tick>0了,换了while的话,之后的线程都会去判断票数是否是大于0的
回复 使用道具 举报
吴杰栋 发表于 2014-7-28 10:39
楼主,你把if变成while试试,13行线程睡眠之后,由于if只会判断一次,那么之前进来的线程就不会去判断tick>0了, ...

还是有0呐。。。
回复 使用道具 举报
Wokno 发表于 2014-7-28 09:59
问题出在你13行代码上,当一个线程卖出最后一张票后,其它三个处于睡眠状态的线程重新获取cpu执行权时,就 ...

Yes,你说的这种情况应该是没有加同步的状况,现第九行有加同步代码块,应该就能解决这个问题。
我现在的疑问:为哈没有解决呐?
回复 使用道具 举报
本帖最后由 Wokno 于 2014-7-28 13:33 编辑
尘埃落定 发表于 2014-7-28 10:57
Yes,你说的这种情况应该是没有加同步的状况,现第九行有加同步代码块,应该就能解决这个问题。
我现在的 ...

加入了同步代码块也是一样,因为每次线程sleep时,它会释放其持有的锁,其它线程就可以拿到锁。你把System.out放在循环内了吧?线程睡醒了后就直接打印了,你把System.out拿到while循环外面就可以了,线程每次睡醒以后就去判断一下票数是否还有效。
回复 使用道具 举报
Wokno 发表于 2014-7-28 13:27
加入了同步代码块也是一样,因为每次线程sleep时,它会释放其持有的锁,其它线程就可以拿到锁。你把System ...

sleep的时候,其他线程应该拿不到锁的吧?我对同步的理解是:只要其中的一个线程进到同步中,如果没有出同步的话,锁都不会放,其他的也就进不去,所以同步才可以解决多线程的安全问题。

而且如果把打印语句拿到外面的话,就只能打印最后一张票了吧
回复 使用道具 举报
Wokno 中级黑马 2014-7-28 15:22:14
8#
尘埃落定 发表于 2014-7-28 13:47
sleep的时候,其他线程应该拿不到锁的吧?我对同步的理解是:只要其中的一个线程进到同步中,如果没有出 ...

额,不好意思,头有点晕,释放锁是:
1.同步代码块执行完成后;
2.抛出异常;
3.调用wait方法。
复习了下。:sleepy:

没注意你前面是继承了Thread类,我还以为是实现了Runnable接口,继承Thread类的话,你的锁也要定义为static的,不然每new一个对象,都会持有自己的一把锁,不过加静态了,每次要让一个线程执行完了才能开始其它线程,这种问题要使用Runnable接口,因为需要多个线程对同一个对象的操作。你可以查查API文档。
回复 使用道具 举报 1 0
首先多个线程同步要有同一个锁,你的代码里,每一个线程的锁都是独立的,也就是说你锁了等于没锁,我帮你改了代码就是
  1. class SaleTicket2 extends Thread
  2. {
  3.                 //Object obj = new Object();
  4.         private static int tick = 100;
  5.         public void run()
  6.         {
  7.                 while(true)
  8.                 {       if(tick > 0)//这里需要判断一下,不然会一直打印最后一张票
  9.                                                         System.out.println("tick="+tick);
  10.                         synchronized(ThreadLockTest.class)//synchronized(obj)
  11.                         {//重点在同步的锁上,需要同一把锁,也就是要同一个对象,你显然没搞清楚
  12.                                 if (tick > 0)
  13.                                 {
  14.                                         try{sleep(10);}catch(Exception e){}
  15.                                         System.out.println(currentThread().getName()+"---sale----+"+tick--);//同步过了,怎么还有0,-1和-2?
  16.                                 }
  17.                         }
  18.                 }
  19.         }
  20. }

  21. class ThreadLockTest
  22. {
  23.         public static void main(String[] args)
  24.         {
  25.                 SaleTicket2 st21 = new SaleTicket2();
  26.                 SaleTicket2 st22 = new SaleTicket2();
  27.                 SaleTicket2 st23 = new SaleTicket2();
  28.                 SaleTicket2 st24 = new SaleTicket2();
  29.                 st21.start();
  30.                 st22.start();
  31.                 st23.start();
  32.                 st24.start();

  33.         }
  34. }
复制代码
回复 使用道具 举报
咸菜+萝卜干 发表于 2014-7-28 19:22
首先多个线程同步要有同一个锁,你的代码里,每一个线程的锁都是独立的,也就是说你锁了等于没锁,我帮你改 ...

o,因为new了两个对象,所以是两把锁。{:3_67:}
回复 使用道具 举报
尘埃落定 发表于 2014-7-28 21:37
o,因为new了两个对象,所以是两把锁。

现在知道了?{:3_47:}
回复 使用道具 举报

恩,以后还是多用实现方式......
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马