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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 史卜坤 中级黑马   /  2012-7-14 22:29  /  1525 人查看  /  3 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

  • class Ticket implements Runnable
  • {
  •         private int ticket = 100;
  •         //private String name;
  •         //Ticket(String name)
  •         //{
  •                 //this.name = name;
  •         //}
  •         public void run()
  •         {
  •                 while(ticket>0)
  •                 {
  •                         try
  •                         {
  •                                 Thread.sleep(10);
  •                         }
  •                         catch(Exception e)
  •                         {
  •                         }
  •                         System.out.println(Thread.currentThread().getName()+"sale..."+ticket--);
  •                 }
  •         }
  • }
  • class ThreadDemo4
  • {
  •         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();
  •         }
  • }

复制代码
毕老师说这个多线程程序有安全问题,还是不太明白。比如线程0执行时的这个ticket=1>0 进入那个while循环打印,这时ticket=0,若线程2抢到这个执行权它不能进入while循环呀!怎么还能打印呢?

评分

参与人数 1技术分 +1 收起 理由
蒋映辉 + 1

查看全部评分

3 个回复

倒序浏览
本帖最后由 周刚 于 2012-7-14 22:52 编辑

线程2抢到这个执行权它不能进入while循环?为什么别人线程不能进入while循环?在执行ticket--之前,所有线程执行while(ticket>0)都成立。当然都会打印!
while代码段并不是线程安全的,并没有加任何锁,可以有多个线程同时执行。如下,我票数设置为1:
class Ticket implements Runnable
{
        private int ticket = 1;
        public void run()
        {
                while(ticket>0)
                {
                        try
                        {
                                Thread.sleep(10);
                        } catch(Exception e){}
                        System.out.println(Thread.currentThread().getName()+"sale..."+ticket--);
                }
        }
}
class ThreadDemo4
{
        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();
        }
}
输出结果如下:
Thread-1sale...1
Thread-3sale...0
Thread-0sale...-1
Thread-2sale...-2

表示四个线程在while语句执行ticket--之前都进入到while方法体内。相当于while(ticket>0)的条件失去的作用。

评分

参与人数 1技术分 +1 收起 理由
蒋映辉 + 1

查看全部评分

回复 使用道具 举报
public void run()
        {
                while(ticket>0)//假如当ticket=1时,t1进来
                {
                        try
                        {
                                Thread.sleep(10);
                                                                //t1执行到这里,暂停执行,t2进来,这时ticket=1,t2可以执行,t2执行到这里,也暂停执行,t3进来
                        }                                      //由于这几个线程进来的时候ticket=1所以可以获得执行权
                        catch(Exception e)
                        {
                        }
                        System.out.println(Thread.currentThread().getName()+"sale..."+ticket--);//如果t3继续执行到这里,就会卖1号票,1号票卖了后,
                                                                                                                                  // ticket--变为0,t3执行完放弃执行权,那么t2就会执行到这里
                                                                                                                        //这样t2卖的票会变成0号,t2执行完之后,ticket--变为-1,t3继续执行到这里,那么t3   
                                                                                                              //卖的票就会变成-1号,它们都不用继续去判断ticket是否大于零这个条件,故可以打印出来
                                                                                                             /这样就出现了安全问题
                }
        }

评分

参与人数 1技术分 +1 收起 理由
蒋映辉 + 1

查看全部评分

回复 使用道具 举报
就假设ticket=1,有四个线程卖票,首先明确:(1)没有对共享数据加锁,任一线程只要拿到执行权都可以走到while语句里面
                                         (2)sleep()的作用:释放CPU执行权,不释放锁,此案例无锁,当执行到sleep(long time)时,线程放弃CPU执行权
                                         (3)ticket--动作是在sleep()之后执行的,当线程执行到sleep()被冻结以后,ticket的值还是为1.
                                                              (4)ticket--动作等同于ticket=ticket--,把ticket的值赋给左边以后,才自减一次
用以下较为极端的一个场景描述:
Thread-0拿到CPU执行权,到sleep(10)被冻结,被Thread-1抢到执行权;
Thread-1执行到sleep(10)也冻结,Thread-2抢到执行权;
Thread-2执行到sleep(10)冻结,Thread-3抢到执行权;
Thread-3执行到sleep(10)冻结;
假若Thread-3冻结以后,sleep()的时间才到,那么第一个被等待的线程Thread-0又重新拿到执行权,执行打印语句,打印为1
后面的相继醒过来,就出现了0,-1,-2


评分

参与人数 1技术分 +1 收起 理由
蒋映辉 + 1

查看全部评分

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马