需求:三个窗口同时售卖50张票
代码如下:
//模拟3个窗口同时售票 class SaleTicket extends Thread{ //定义票数 int num = 50; public SaleTicket(String name) { super(name); } @Override public void run() { while (true) { if(num>0) { System.out.println(Thread.currentThread().getName()+"买了"+num+"号票"); num--; }else { System.out.println(Thread.currentThread().getName()+"票卖完了"); break; } } } } public class Demo5 { public static void main(String[] args) { SaleTicket sale1 = new SaleTicket("窗口1"); SaleTicket sale2 = new SaleTicket("窗口2"); SaleTicket sale3 = new SaleTicket("窗口3"); sale1.start(); sale2.start(); sale3.start(); } }
疑问:怎么每个窗口都卖了50号的票,本来只有50张票,怎么卖出了150张的票呢?
原因:因为票数是静态的成员变量,静态的成员变量会在每个对象中都会维护一份数据
解决方案:把票数变成静态的成员变量,共享给三个对象
代码如下:
//模拟3个窗口同时售票 class SaleTicket extends Thread{ //定义票数 static int num = 50; public SaleTicket(String name) { super(name); } @Override public void run() { while (true) { if(num>0) { System.out.println(Thread.currentThread().getName()+"买了"+num+"号票"); num--; }else { System.out.println(Thread.currentThread().getName()+"票卖完了"); break; } } } } public class Demo5 { public static void main(String[] args) { SaleTicket sale1 = new SaleTicket("窗口1"); SaleTicket sale2 = new SaleTicket("窗口2"); SaleTicket sale3 = new SaleTicket("窗口3"); sale1.start(); sale2.start(); sale3.start(); } }
疑问:怎么又把50号票卖了三次呢?难道问题还没解决?
原因:其实把票数设置成了静态后,确实解决了每个对象都维护一份数据的现象(可以看出只买了50次,而不是150次)
此图的数据不同,但是原理一样(不要注重细节嘛!!)
当线程1刚运行到输出语句并输出了卖了多少号票,还没执行num--这个语句的时候,cup被线程3抢夺了
当线程3执行了一个完整的循环(输出了,num也减一了)后,cup被线程1抢了,并执行了num--
者时候cup被线程3抢夺了,并输出了语句.....(后面原理差不多)
总结出现线程安全问题的原因:
1.存在至少2个线程共享一个资源
2.存在至少2句语句操作同一个共享资源
下一篇笔录会讲解如何解决此问题