黑马程序员技术交流社区

标题: 线程安全问题 [打印本页]

作者: 史卜坤    时间: 2012-7-14 22:29
标题: 线程安全问题

复制代码
毕老师说这个多线程程序有安全问题,还是不太明白。比如线程0执行时的这个ticket=1>0 进入那个while循环打印,这时ticket=0,若线程2抢到这个执行权它不能进入while循环呀!怎么还能打印呢?
作者: 周刚    时间: 2012-7-14 22:51
本帖最后由 周刚 于 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)的条件失去的作用。


作者: 王冰    时间: 2012-7-14 23:26
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是否大于零这个条件,故可以打印出来
                                                                                                             /这样就出现了安全问题
                }
        }
作者: 柯玲    时间: 2012-7-14 23:46
就假设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







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