卖票案例

需求:某电影院共有100张票,共有3个窗口买票,请设置一个程序模拟该电影院卖票

思路: 1、定义一个SellTicket类实现Runnable接口,里面定义一个成员变量:private int tickets = 100 2、在SellTicket类中重写run()方法实现卖票,代码步骤如下 (1)判断票数大于0,就卖票,并告知是哪个窗口卖的 (2)卖了票之后,总票数要减1 (2)票卖完了,也可能有人来问,所以这里用死循环让卖票的动作一直执行 3、定义一个测试类,里面有一个main方法,代码步骤如下 (1)创建SellTicket类的对象 (2)创建三个Thread类的对象,把SellTicket对象作为构造方法的参数,并给出对应的窗口名称 (3)启动线程

 

卖票案例的练习

 

卖票案例的思考

对于上一个卖票的案例,我们可以发现如下不足,并给出解决方法 在实际生活中,售票时出票也是需要时间的,所以在出售一张票的时候,需要一点的时间延迟 解决:在"a_11_1SellTicket"每次出票时间间隔设置为100毫秒,用sleep()方法实现

还存在如下问题,并给出原因分析: 第一个问题:相同的票出现了多次 第二个问题:出现了负数的票 原因:t1线程抢到CPU执行权时,进入了100毫秒的休眠,此时t2线程也抢到了执行权,然后t2也会进入休眠,t3同理。 假设3个线程按照顺序醒过来,那么t1会再次抢到CPU的执行权并在控制台输出"窗口1正在出售第100张票" 在t1将要执行减减操作时,如果t2已经抢到CPU执行权,那t2就会在t1执行减减操作之前在控制台输出"窗口2正在出售第100张票" 在t1和t2将要执行减减操作时,如果t3已经抢到CPU执行权,那t3就会在t1和t2执行减减操作之前在控制台输出"窗口3正在出售第100张票"。 就出现了相同票数卖了3次的情况。 注意最后减减操作被3个线程都执行了一次,所以就会导致多执行2次,于是就多减了2次,到票卖完时原来预期是会减到1,此时就会导致减到-1

上面那两个问题解决方法的分析如下 在线程按照顺序醒过来之后,t1抢到了CPU的执行权,输出"窗口1正在出售第100张票" 且假设t1继续拥有CPU的执行权,就会执行tickets减减操作,此时tickets就从1变成了0,0不满足if循环,所以线程1在tickets减减之后不会再进入if语句 此时t2线程抢到了CPU的执行权,在控制台输出"窗口2正在出售第0张票" 且假设t2继续拥有CPU的执行权,就会执行tickets减减操作,此时tickets就从0变成了-1,-1不满足if循环,所以线程2在tickets减减之后不会再进入if语句 然后t3线程抢到了CPU的执行权,在控制台输出"窗口3正在出售第-1张票" 且假设t3继续拥有CPU的执行权,就会执行tickets减减操作,此时tickets就从-1变成了-2,-2不满足if循环,所以线程3在tickets减减之后不会再进入if语句

所有问题的原因:线程执行的随机性导致的

 

卖票案例思考的练习

 

卖票_同步代码块解决数据安全

为什么出现问题?(这也是我们判断多线程程序是否会有数据安全问题的标准) 1、是否是多线程环境 2、是否有共享数据 3、是否有'多条语句操作共享数据' 只有同时满足上面3个条件才会出现数据安全问题

如何解决数据安全问题,如下 基本思想:让程序没有安全问题的环境,即破坏掉上面3个条件中的其中一个即可。前面2个条件我们破坏不了,只能破坏第3个条件

怎么破坏第3个条件,如下 1、把'多条语句操作共享数据'的代码给锁起来,让任意时刻只能有一个线程执行即可。即把if语句锁起来 2、Java提供了同步代码块的方式来解决 注意:多线程只是在操作临界资源时是单线程

什么是同步代码块,格式如下。synchronized[ˈsɪŋkrənaɪzd] 使同步;同速运行

synchronized(任意对象):就相当于给代码加锁了,任意对象就可以看成是一把锁 注意要让多个线程去使用同一把锁,具体代码在"a_12_1SellTicket"类,把if语句锁起来

给if语句加锁之后,只能有一个线程在if语句里面执行,当这个线程执行完毕之后,if锁就会被释放,t2或t3线程就会进入if循环,...

 

同步的好处和弊端: 好处:解决了多线程的数据安全问题 弊端:当线程很多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率

 

卖票_同步代码块解决数据安全的练习

 

卖票_同步方法解决数据安全

同步方法:就是把synchronized关键字加到方法上,格式如下 修饰符 synchronized 返回值类型 方法名(方法参数){}

同步对象的锁对象是:this

同步静态方法:就是把synchronized关键字加到静态方法上。格式如下

同步静态方法的锁对象是:对应类名.class

 

 

卖票_同步方法解决数据安全的练习