java多线程之铁路售票系统

Java多线程之铁路售票系统攻略

一、需求分析

铁路售票系统需要满足的主要需求:

  • 售票窗口可以同时售卖多张票,需要支持并发访问。
  • 售票系统需要保证售卖的票数不能超过存库量。
  • 当售票系统资源被其他线程占用时,需要等待其他线程执行完毕后才能获取资源。

二、设计思路

根据需求,我们可以采用以下设计思路:

  1. 定义 Ticket 类表示火车票,其中包括车次、出发时间、座位号等信息。
  2. 定义 TicketDatabase 类表示火车票库存,其中包括每种车次的剩余票数、已售票数等信息。
  3. 定义两个线程类:SellerThread 类表示售票窗口的线程,它们可以并发访问售票系统;CheckerThread 类表示检票员线程,用于检票。
  4. 在 SellerThread 线程中实现售票逻辑,包括从 TicketDatabase 中获取库存、判断是否售出已售光、实现售票等操作。
  5. 在 CheckerThread 线程中实现检票逻辑,包括检票、验证车票有效性等操作。

三、代码实现

1. Ticket 类

public class Ticket {
    private String trainNo; // 车次
    private String departureTime; // 出发时间
    private String seatNo; // 座位号

    public Ticket(String trainNo, String departureTime, String seatNo) {
        this.trainNo = trainNo;
        this.departureTime = departureTime;
        this.seatNo = seatNo;
    }

    public String getTrainNo() {
        return trainNo;
    }

    public String getDepartureTime() {
        return departureTime;
    }

    public String getSeatNo() {
        return seatNo;
    }
}

2. TicketDatabase 类

public class TicketDatabase {
    private final Map<String, Integer> ticketStock = new ConcurrentHashMap<>();

    public TicketDatabase(List<String> trains) {
        for (String train : trains) {
            ticketStock.put(train, 100); // 初始库存为 100 张
        }
    }

    public boolean bookTicket(String trainNo) {
        int stock = getStock(trainNo);
        if (stock > 0) {
            ticketStock.put(trainNo, stock - 1);
            return true;
        }
        return false;
    }

    public int getStock(String trainNo) {
        return ticketStock.getOrDefault(trainNo, 0);
    }
}

3. SellerThread 类

public class SellerThread extends Thread {
    private final TicketDatabase ticketDatabase;

    public SellerThread(TicketDatabase ticketDatabase) {
        this.ticketDatabase = ticketDatabase;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (ticketDatabase) {
                if (ticketDatabase.getStock("G1001") == 0) {
                    break; // 如果该车次已售光,则结束售票
                }
                if (ticketDatabase.bookTicket("G1001")) {
                    System.out.println(Thread.currentThread().getName() + ": " + "售票成功!");
                } else {
                    System.out.println(Thread.currentThread().getName() + ": " + "售票失败!");
                }
            }
        }
    }
}

4. CheckerThread 类

public class CheckerThread extends Thread {
    private final TicketDatabase ticketDatabase;

    public CheckerThread(TicketDatabase ticketDatabase) {
        this.ticketDatabase = ticketDatabase;
    }

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(50); // 等待 50ms
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (ticketDatabase) {
                System.out.println("检票员检票: " + ticketDatabase.getStock("G1001"));
            }
        }
    }
}

5. 示例说明

以下是两条示例说明:

示例一

我们创建两个售票窗口线程和一个检票员线程,同时设置库存为 101 张。预期输出结果如下:

售票窗口1: 售票成功!
售票窗口2: 售票成功!
售票窗口1: 售票成功!
售票窗口2: 售票成功!
售票窗口1: 售票成功!
售票窗口2: 售票成功!
售票窗口1: 售票成功!
售票窗口2: 售票成功!
售票窗口1: 售票成功!
售票窗口2: 售票成功!
检票员检票: 91
检票员检票: 89
检票员检票: 87
检票员检票: 85
检票员检票: 83
检票员检票: 81
检票员检票: 79
检票员检票: 77
检票员检票: 75
检票员检票: 73
检票员检票: 71
检票员检票: 69
检票员检票: 67
检票员检票: 65
检票员检票: 63
检票员检票: 61
检票员检票: 59
检票员检票: 57
检票员检票: 55
检票员检票: 53
检票员检票: 51
检票员检票: 49
检票员检票: 47
检票员检票: 45
检票员检票: 43
检票员检票: 41
检票员检票: 39
检票员检票: 37
检票员检票: 35
检票员检票: 33
检票员检票: 31
检票员检票: 29
检票员检票: 27
检票员检票: 25
检票员检票: 23
检票员检票: 21
检票员检票: 19
检票员检票: 17
检票员检票: 15
检票员检票: 13
检票员检票: 11
检票员检票: 9
检票员检票: 7
检票员检票: 5
检票员检票: 3
检票员检票: 1

代码如下:

public static void main(String[] args) {
    List<String> trains = Arrays.asList("G1001");
    TicketDatabase ticketDatabase = new TicketDatabase(trains);
    SellerThread seller1= new SellerThread(ticketDatabase);
    SellerThread seller2 = new SellerThread(ticketDatabase);
    CheckerThread checker = new CheckerThread(ticketDatabase);
    seller1.start();
    seller2.start();
    checker.start();
}

示例二

我们创建三个售票窗口线程和一个检票员线程,同时设置库存为 2 张。预期输出结果如下:

售票窗口2: 售票成功!
售票窗口1: 售票成功!
售票窗口3: 售票失败!
售票窗口3: 售票失败!
检票员检票: 0

代码如下:

public static void main(String[] args) {
    List<String> trains = Arrays.asList("G1001");
    TicketDatabase ticketDatabase = new TicketDatabase(trains);
    SellerThread seller1= new SellerThread(ticketDatabase);
    SellerThread seller2 = new SellerThread(ticketDatabase);
    SellerThread seller3 = new SellerThread(ticketDatabase);
    CheckerThread checker = new CheckerThread(ticketDatabase);
    seller1.start();
    seller2.start();
    seller3.start();
    checker.start();
}

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:java多线程之铁路售票系统 - Python技术站

(0)
上一篇 2023年5月19日
下一篇 2023年5月19日

相关文章

  • java实现简易超市管理系统 附源码下载

    Java实现简易超市管理系统攻略 实现思路 本超市管理系统的主要功能包括如下: 实现商品的库存管理功能,包括商品的入库、出库和查询等操作。 实现商品的销售管理功能,包括购物车、结算和打印小票等操作。 实现系统的用户管理功能,包括用户登录和登出、用户信息修改等操作。 根据上述需求,我们可以把整个系统分成三大模块:商品管理模块、销售管理模块和用户管理模块。每个模…

    Java 2023年5月18日
    00
  • 举例讲解Java中Piped管道输入输出流的线程通信控制

    讲解Java中Piped管道输入输出流的线程通信控制的攻略如下: 什么是Piped管道输入输出流 Java中的Piped输入输出流是一种基于管道(pipe)的流方式。管道是一种常见的进程间通信(IPC)的方式。Piped输入输出流提供了一个可以连接线程的管道,其中一个线程通过写入实现输出流的数据传递,而另一个线程通过读取实现输入流的数据读取。 Piped的使…

    Java 2023年5月26日
    00
  • JavaSpringBoot报错“ConversionNotSupportedException”的原因和处理方法

    原因 “ConversionNotSupportedException” 错误通常是以下原因引起的: 类型转换错误:如果您的类型转换错误,则可能会出现此。在这种情况下,您需要检查您的类型转换并确保它们正确。 类型转换不支持:如果您的类型转换不支持,则可能会出现此。在这种情况下,您需要检查您的类型转换并确保它们受支持。 解决办法 以下是解决 “Conversi…

    Java 2023年5月4日
    00
  • SpringBoot集成Shiro进行权限控制和管理的示例

    下面我来详细讲解“SpringBoot集成Shiro进行权限控制和管理的示例”的完整攻略。 什么是 Shiro Apache Shiro 是一个功能强大且易于使用的 Java 安全框架,提供身份验证、授权、加密等功能,可以轻松地保护应用程序的安全与隐私。 SpringBoot 集成 Shiro 下面是 SpringBoot 集成 Shiro 进行权限控制和管…

    Java 2023年6月15日
    00
  • java和jsp之间的request传值方法

    介绍Java和JSP之间的request传值方法,主要有三种:参数,属性和Session。 1. 参数 使用参数的方法最为简单,只需要在传值的时候,将值通过URL的参数形式传递过去即可。JSP页面中获取参数值的方法是通过request.getParameter()方式。 示例1:将参数id传递给另一个JSP页面 <a href="page2.…

    Java 2023年6月15日
    00
  • Java实现ZooKeeper的zNode监控

    当我们使用ZooKeeper作为分布式协调框架时,监视zNode的变化是很常见的任务,因为zNode的变化往往意味着某些与服务相关的状态变化。本文将详细讲解如何使用Java实现ZooKeeper的zNode监视。 步骤一:导入ZooKeeper依赖 首先,在项目的pom.xml文件中添加以下ZooKeeper依赖: <dependency> &l…

    Java 2023年5月19日
    00
  • Java实战之用hutool-db实现多数据源配置

    当我们的应用需要连接多个数据库时,常规的做法是通过JDBC来手动连接和操作不同的数据源。这样的代码通常会显得冗长和重复,对于代码维护和可读性都造成了一定的负担。事实上,Java中有一些工具库可以帮助我们更容易地实现多数据源配置和自动化操作,比如常用的HikariCP、Druid等数据库连接池,还有hutool-db库。 Hutool-db简介 Hutool-…

    Java 2023年5月20日
    00
  • MyBatis如何使用(三)

    MyBatis是一款轻量化的ORM框架,它简化了Java开发者对关系数据库的访问操作,同时还能够灵活地支持复杂的SQL映射操作,让开发者能够更加专注于业务逻辑开发。 本文将详细讲解MyBatis的使用方法,主要包含以下内容: 1. MyBatis的基本使用 使用MyBatis需要进行如下几个步骤: 1.1 依赖导入 在项目的pom.xml文件中,添加MyBa…

    Java 2023年5月26日
    00
合作推广
合作推广
分享本页
返回顶部