java多线程模拟实现12306售票

这里写自定义目录标题


业务描述
假设有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);
}
上一篇:12306的“短信公众号”到底是个啥?


下一篇:全网首发:12306抢票算法大曝光?(十张图搞定)