经典案例 – Java·卖票问题
实现卖票中多个窗口同时买一张票,实际100张票卖出去100多张票等一系列问题
volatile
//volatile关键字在卖票例子中表现
public class TicketWindows implements Runnable {
private volatile int ticket = 100; // 一百张票,用volatile修饰
@Override
public void run() {
// 重写run方法,模拟卖票,通过下面我们可以发现:对一个共享资源可以多个线程同时进行修改,自然就会有线程安全问题。
while (true){
if (ticket > 0){
try {
Thread.sleep(100); //多个线程同时判断到“ticket>0”,然后休眠
}catch (InterruptedException e){
e.printStackTrace();
}
//多个线程同时唤醒,并且同时进行ticket--操作
System.out.println(Thread.currentThread().getName() + "卖出一张票,当前票数:" + ticket--);
}else break;
}
}
}
//测试类
public class TestVolatile {
public static void main(String[] args) {
TicketWindows tw = new TicketWindows();
Thread t1 = new Thread(tw);
Thread t2 = new Thread(tw);
Thread t3 = new Thread(tw);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
[外链图片转存中…(img-QSAv3lvm-1724572491379)]
synchronized
//卖票窗口
public class Ticket {
static int tCount = 100; // 默认票数100张
public synchronized boolean gettCount() {
//返回是否有余票
return tCount > 0;
}
public synchronized void saleT(int n, String name) {
if (tCount - n >= 0) {
tCount -= n;
System.out.println(name + ":出售" + n + "张票成功!目前还剩" + tCount + "张票~");
try {
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
} else if (tCount != 0) {
//如果第一个判断买票数量大于余票数量,但还有票
System.out.println(name +":抱歉!购买" + n + "张票失败!目前仅剩" + tCount + "张!");
} else System.out.println(name +":抱歉!票已售空~");
}
}
//测试类
public class TestBuyTicket {
public static void main(String[] args) {
// 创建售票对象
Ticket ticket = new Ticket();
// 创建3个售票窗口线程
Thread ck1 = new Thread("窗口1") {
@Override
public void run() {
while (ticket.gettCount())
// 限制每次购票最多5张
ticket.saleT((int) (Math.random() * 5) + 1, Thread.currentThread().getName());
}
};
Thread ck2 = new Thread("窗口2") {
@Override
public void run() {
while (ticket.gettCount())
// 限制每次购票最多5张
ticket.saleT((int) (Math.random() * 5) + 1, Thread.currentThread().getName());
}
};
Thread ck3 = new Thread("窗口3") {
@Override
public void run() {
while (ticket.gettCount())
// 限制每次购票最多5张
ticket.saleT((int) (Math.random() * 5) + 1, Thread.currentThread().getName());
}
};
ck1.start();
ck2.start();
ck3.start();
}
}
}
};
ck1.start();
ck2.start();
ck3.start();
}
}