Day30 线程安全之窗口售票问题(含代码)
一、需求:
铁道部发布了一个售票任务,要求销售1000张票,要求有3个窗口来进行销售,
请编写多线程程序来模拟这个效果( 注意:使用线程类的方式解决该需求)
窗口001正在销售第1张票
窗口001正在销售第2张票
窗口002正在销售第3张票
。。。
窗口002正在销售第1000张票
窗口002票已售完
窗口001票已售完
窗口003票已售完
二、问题一
1、问题一:
三个窗口各卖1000张票,一共卖了3000张
2、相关代码:
package com.qf;
public class MyThread extends Thread {
public MyThread(String name) {
// TODO 自动生成的构造函数存根
super(name);
}
@Override
public void run() {
// TODO 自动生成的方法存根
int allTicket=1000;
int curTicket=0;
while (curTicket<allTicket) {
curTicket++;
System.out.println("窗口"+Thread.currentThread().getName()+"正在出售"+curTicket+"第几张票");
}
}
}
public class Test01 {
public static void main(String[] args) {
MyThread myThread1 = new MyThread("001");
MyThread myThread2 = new MyThread("002");
MyThread myThread3 = new MyThread("003");
myThread1.start();
myThread2.start();
myThread3.start();
}
}
出现的问题:
3、出现原因:
allTicket和curTicket是run方法的局部变量,三个线程抢到CPU资源后,都会调用run方法,run方法被调用了3次,所以卖了3000张票。
4、解决方案:
将allTicket和curTicket设置为静态变量,让三个线程共享
三、问题二
1、问题二:
有些票没有卖,有些票卖了重票
2、相关代码:
package com.qf;
public class MyThread extends Thread {
private static int allTicket=1000;
private static int curTicket=0;
public MyThread(String name) {
// TODO 自动生成的构造函数存根
super(name);
}
@Override
public void run() {
// TODO 自动生成的方法存根
while (curTicket<allTicket) {
curTicket++;
System.out.println("窗口"+Thread.currentThread().getName()+"正在出售"+curTicket+"第几张票");
}
}
}
public class Test01 {
public static void main(String[] args) {
MyThread myThread1 = new MyThread("001");
MyThread myThread2 = new MyThread("002");
MyThread myThread3 = new MyThread("003");
myThread1.start();
myThread2.start();
myThread3.start();
}
}
出现问题:
3、出现原因:
当前线程抢到CPU资源后做了票的自增,但是还没来得及输出,时间片到了就退出CPU资源,然后其他线程抢到CPU资源了。
4、解决方案:
当前线程抢到CPU资源后,票的自增和输出执行完毕才能切换到其他线程运行 – 加锁。
四、问题三
1、问题三:
多卖了票。
2、相关代码:
package com.qf;
public class MyThread extends Thread {
private static int allTicket=1000;
private static int curTicket=0;
private static Object obj = new Object();
public MyThread(String name) {
// TODO 自动生成的构造函数存根
super(name);
}
@Override
public void run() {
// TODO 自动生成的方法存根
while (curTicket<allTicket) {
synchronized (obj) {
curTicket++;
System.out.println("窗口"+Thread.currentThread().getName()+"正在出售"+curTicket+"第几张票");
}
}
}
}
public class Test01 {
public static void main(String[] args) {
MyThread myThread1 = new MyThread("001");
MyThread myThread2 = new MyThread("002");
MyThread myThread3 = new MyThread("003");
myThread1.start();
myThread2.start();
myThread3.start();
}
}
出现问题:
3、出现原因:
curTicket到了临界点(999),三个线程都可以进判断,然后上锁。
4、解决方案:
在锁中再次判断。
完整代码:
package com.qf;
public class MyThread extends Thread {
private static int allTicket=1000;
private static int curTicket=0;
private static Object obj = new Object();
public MyThread(String name) {
// TODO 自动生成的构造函数存根
super(name);
}
@Override
public void run() {
// TODO 自动生成的方法存根
while (curTicket<allTicket) {
synchronized (obj) {
if(curTicket < allTicket){
curTicket++;
System.out.println("窗口" + Thread.currentThread().getName() + "正在销售第" + curTicket + "张票");
}
if(curTicket >= allTicket){
System.out.println("窗口" + Thread.currentThread().getName() + "票已经售完");
}
}
}
}
}
public class Test01 {
public static void main(String[] args) {
MyThread myThread1 = new MyThread("001");
MyThread myThread2 = new MyThread("002");
MyThread myThread3 = new MyThread("003");
myThread1.start();
myThread2.start();
myThread3.start();
}
}
args) {
MyThread myThread1 = new MyThread("001");
MyThread myThread2 = new MyThread("002");
MyThread myThread3 = new MyThread("003");
myThread1.start();
myThread2.start();
myThread3.start();
}
}