这里写自定义目录标题
业务描述
假设有200张票,用4个线程去订票,不能有两个或者以上的线程订到了
同一个票(原因就不说了),当最后一张票卖掉的时候结束,再订就抛
异常提示出票卖完了。
业务分析,要实现以上功能,
1、需要创建一个车票类,初始化票,卖票的接口
2、自定义异常的一个类。
3、创建卖票线程类,在run方法中卖车票。
*4、初始化车票的线程,负责初始化车票,也就是初始化Ticket类中的数组。
5、创建主方法进行测试。
public class Test {
public static void main(String[] args) throws TicketIsEmpty {
//创建票仓对象,设置上限为200张车票
Shop myshop = new Shop(200);
//创建票仓线程
Thread t1 = new Thread(myshop);
//创建售票窗口1
TicketSeller ticketSeller1 = new TicketSeller("张三",myshop);
//创建售票窗口2
TicketSeller ticketSeller2 = new TicketSeller("李四",myshop);
//创建售票窗口3
TicketSeller ticketSeller3 = new TicketSeller("王五",myshop);
//创建售票窗口4
TicketSeller ticketSeller4 = new TicketSeller("赵六",myshop);
//等待车票初始化完成后再开始售票
t1.setName("车票初始化线程");
t1.start();
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
//创建售票线程
Thread t2 = new Thread(ticketSeller1);
t2.setName("售票窗口1");
Thread t3 = new Thread(ticketSeller2);
t3.setName("售票窗口2");
Thread t4 = new Thread(ticketSeller3);
t4.setName("售票窗口3");
Thread t5 = new Thread(ticketSeller4);
t5.setName("售票窗口4");
//开始售票
t2.start();
t3.start();
t4.start();
t5.start();
}
}
public class Ticket implements Saleable{
//车票名字
private String name;
//车票状态
boolean state;
//售票窗口
private TicketSeller ticketSeller;
//构造方法
public Ticket(String name, boolean state) {
this.name = name;
this.state = state;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//获取车票状态
public String getState() {
return state?"未售出":"已售出";
}
//设置车票状态
public void setState(boolean state) {
this.state = state;
}
//线程安全设置,保证不会一票多卖,并且关联售票窗口
public synchronized void saleTicket(TicketSeller ticketSeller){
this.ticketSeller = ticketSeller;
//理论来说不会走此分支
if(ticketSeller ==null){
System.out.println("请先设置销售窗口!");
return;
}
if(state){
//把车票信息改为已售出
this.setState(false);
}else{
System.out.println("错误,该车票已售出!");
}
}
//重写toString()方法
public String toString() {
return name + ": " + getState();
}
}
public class TicketSeller implements Runnable {
//售票员名字
private String sellerName;
//车票
private Ticket ticket;
//票仓
private Shop shop;
private int sold = 0;
//构造方法
public TicketSeller(String sellerName, Shop shop) {
this.sellerName = sellerName;
this.shop = shop;
}
//获取售票员名字
public String getSellerName() {
return sellerName;
}
//设置售票员名字
public void setSellerName(String sellerName) {
this.sellerName = sellerName;
}
//获取售票员销售的车票
public Ticket getTicket() {
return ticket;
}
//设置车票
public void setTicket(Ticket ticket) {
this.ticket = ticket;
}
//获取票仓对象
public Shop getShop() {
return shop;
}
//设置票仓
public void setShop(Shop shop) {
this.shop = shop;
}
@Override
public void run() {
//判断票仓是否为设置,在构造方法中有设置,理论来说不会走这个分支
if (this.shop == null) {
System.out.println("请先设置票仓!");
return;
}
//执行售票循环,除非接收到票仓生成车票的异常,否则一直循环
while (true) {
try {
//获取票仓生成的车票
ticket = shop.generateTicket(this);
//售出车票
ticket.saleTicket(this);
//控制台监控信息
System.out.println(Thread.currentThread().getName() + " 的 " + sellerName + " 售出了 " + ticket.getName());
sold++;
} catch (TicketIsEmpty ticketIsEmpty) {
System.out.println(Thread.currentThread().getName() + "尝试继续售票,因车票库存已空,售票异常终止。累计售出 "
+ sold + " 张车票。");
//ticketIsEmpty.printStackTrace();
//刚开始学,我也不知道为什么不加break会死循环,
//感觉是和while(true)有关系
break;
}
}
}
@Override
public String toString() {
return sellerName;
}
}
public class Shop implements Runnable {
//票仓
private Ticket[] tickets;
//售票窗口
private TicketSeller ticketSeller;
//车票总数
private int index;
//已售出车票数量
private int ticketsold = 0;
//剩余车票数量
private int ticketBalance;
//构造方法
public Shop(int index) {
this.index = index;
ticketBalance = index - ticketsold;
}
public Ticket[] getTickets() {
return tickets;
}
public void setTickets(Ticket[] tickets) {
this.tickets = tickets;
}
public TicketSeller getTicketSeller() {
return ticketSeller;
}
public void setTicketSeller(TicketSeller ticketSeller) {
this.ticketSeller = ticketSeller;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
public int getTicketsold() {
return ticketsold;
}
public void setTicketsold(int ticketsold) {
this.ticketsold = ticketsold;
}
public int getTicketBalance() {
return ticketBalance;
}
public void setTicketBalance(int ticketBalance) {
this.ticketBalance = ticketBalance;
}
//生成即将出售的车票
public Ticket generateTicket(TicketSeller ticketSeller) throws TicketIsEmpty {
//关联售票窗口
this.ticketSeller = ticketSeller;
//判断是否存在售票窗口,理论不会走这个分支
if(ticketSeller == null){
System.out.println("请先设置售票窗口!");
System.exit(0);
}
//如果票还有额度剩余就生成车票
if (ticketBalance > 0) {
int ticketNum = ticketsold;
//售出车票数量+1
ticketsold++;
//车票库存更新
ticketBalance = index - ticketsold;
//把生成的车票返回给售票窗口
return tickets[ticketNum];
} else {
//如果车票没有库存了,抛出异常
throw new TicketIsEmpty();
}
}
@Override
public void run() {
//按照预设的库存上限生成车票库存
tickets = new Ticket[index];
//初始化每张车票的信息,并且全部设置为可出售
for (int i = 0; i < index; i++) {
tickets[i] = new Ticket("第 "+(i+1) + " 号车票", true);
}
System.out.println(Thread.currentThread().getName() + "----->完成,共有 " + index + " 张车票未售出。");
}
}
//自定义异常类
public class TicketIsEmpty extends Exception{
public TicketIsEmpty() {
super();
}
public TicketIsEmpty(String message) {
super(message);
}
}
//自定义售票接口
public interface Saleable {
public void saleTicket(TicketSeller ticketSeller);
}