18-继承Thread类的方式卖电影票案例
需求:
某电影院目前正在上映贺岁大片,共有100张票,而它有3个售票窗口售票,请设计一个程序模拟该电影院售票。
两种方式实现
继承Thread类
实现Runnable接口
注意:此代码只是为了配合学习此小结,仍不完善
1 public class day23_18继承Thread类的方式卖电影票案例 { 2 public static void main(String[] args) { 3 //创建线程对象 4 SellTicket1 st1=new SellTicket1(); 5 SellTicket1 st2=new SellTicket1(); 6 SellTicket1 st3=new SellTicket1(); 7 8 //给线程对象起名字 9 st1.setName("窗口1"); 10 st2.setName("窗口2"); 11 st3.setName("窗口3"); 12 13 //启动线程 14 st1.start(); 15 st2.start(); 16 st3.start(); 17 18 } 19 20 } 21 22 class SellTicket1 extends Thread { 23 // 为了让多个线程对象共享这个100张票,其实应该用静态修饰 24 private static int ticket = 100; 25 26 @Override 27 public void run() { 28 // int ticket=100;这样写每个线程进来都会走到这里,每个线程对象相当于买的是自己的那100张票,不合理,所以应该定义到外面 29 // while(true)是为了模拟一直有票 30 while (true) { 31 if (ticket > 0) { 32 System.out.println(getName() + "正在出售第" + (ticket--) + "张票"); 33 } 34 } 35 36 } 37 }
19-实现Runnable接口的方式卖电影票案例
注意:此代码只是为了配合学习此小结,仍不完善
1 public class day23_19实现Runnable接口的方式卖电影票案例 { 2 3 public static void main(String[] args) { 4 SellTicket2 st = new SellTicket2(); 5 Thread t1 = new Thread(st, "窗口1"); 6 Thread t2 = new Thread(st, "窗口2"); 7 Thread t3 = new Thread(st, "窗口3"); 8 t1.start(); 9 t2.start(); 10 t3.start(); 11 12 } 13 14 } 15 16 class SellTicket2 implements Runnable { 17 // 定义100张票 18 private int tickets = 100; 19 20 @Override 21 public void run() { 22 while (true) { 23 if (tickets > 0) { 24 System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "张票"); 25 } 26 } 27 28 } 29 30 }
20-卖电影票出现了同票和负数票的原因分析
- 我们前面讲解过电影院售票程序,从表面上看不出什么问题,但是在真实生活中,售票时网络是不能实施传输的,总是存在延迟的情况,所以,在出售一张票以后,需要一点时间的延迟
- 改实现接口方式的卖票程序:每次卖票延迟100毫秒
1 public class day23_20卖电影票出现了同票和负数票的原因分析 { 2 public static void main(String[] args) { 3 SellTicket3 st = new SellTicket3(); 4 Thread t1 = new Thread(st, "窗口1"); 5 Thread t2 = new Thread(st, "窗口2"); 6 Thread t3 = new Thread(st, "窗口3"); 7 t1.start(); 8 t2.start(); 9 t3.start(); 10 11 } 12 } 13 class SellTicket3 implements Runnable { 14 // 定义100张票 15 private int tickets = 100; 16 17 @Override 18 public void run() { 19 while (true) { 20 if (tickets > 0) { 21 try { 22 Thread.sleep(100); 23 } catch (InterruptedException e) { 24 e.printStackTrace(); 25 } 26 System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "张票"); 27 } 28 } 29 30 } 31 32 }
实现Runnable接口的方式实现
通过加入延迟后,就产生了2个问题:
A:相同的票卖了多次
CPU的一次操作必须是原子性的
B:出现了负数票
随机性和延迟导致的
21-线程安全问题的产生原因分析
●首先想为什么出现问题?(也是我们判断是否有问题的标准)
●是否是多线程环境
●是否有共享数据
●是否有多条语句搡作共享数据
如何解决多线程安全问题呢?
把多个语句操作共享数据的代码给锁起来,让任意时刻只能有一个线程执行即可。
22-同步代码块的方式解决线程安全问题
思想:
把多条语句操作共享数据的代码给包成一个整体,让某个线程在执行的时候,别人不能来执行。
问题是我们不知道怎么包啊?其实我也不知道,但是Java给我们提供了:同步机制。
同步代码块:
synchronized (对象) {
需要同步的代码;
}
注意:
同步可以解决安全问题的根本原因就在那个对象上。该对象如同锁的功能。
多个线程必须是同一把锁。
1 public class day23_22同步代码块的方式解决线程安全问题 { 2 public static void main(String[] args) { 3 SellTicket4 st = new SellTicket4(); 4 Thread t1 = new Thread(st, "窗口1"); 5 Thread t2 = new Thread(st, "窗口2"); 6 Thread t3 = new Thread(st, "窗口3"); 7 t1.start(); 8 t2.start(); 9 t3.start(); 10 11 } 12 } 13 class SellTicket4 implements Runnable { 14 // 定义100张票 15 private int tickets = 100; 16 //创建锁对象 注意一定要让锁变成一个共享的东西 17 private Object obj=new Object(); 18 19 @Override 20 public void run() { 21 while (true) { 22 synchronized (obj) { 23 if (tickets > 0) { 24 try { 25 Thread.sleep(100); 26 } catch (InterruptedException e) { 27 e.printStackTrace(); 28 } 29 System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "张票"); 30 } 31 32 } 33 } 34 35 } 36 37 }