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();
}
阅读剩余 80%

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

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

相关文章

  • Springboot 通过FastJson实现bean对象和Json字符串互转问题

    下面是详细讲解“Springboot 通过FastJson实现bean对象和Json字符串互转问题”的攻略: 1. 添加FastJson依赖 要使用FastJson完成bean对象和Json字符串的互转,需要在Springboot项目中添加FastJson依赖。在项目的pom.xml中添加以下依赖: <dependency> <groupI…

    Java 2023年5月26日
    00
  • 浅析Java中print、printf、println的区别

    浅析Java中print、printf、println的区别 概述 在Java编程中,我们经常需要在程序中输出信息。而输出信息的方式,主要有三种:print、printf、println。这三种方式虽然非常相似,但是却有着不同的用途和输出效果。本文将详细分析它们之间的区别。 print print是最常用的输出语句之一,用于输出字符串和变量的值。它的使用语法…

    Java 2023年5月26日
    00
  • spring boot 日志配置详解

    Spring Boot是一个快速开发框架,可以帮助开发人员快速构建Web应用程序。在开发过程中,日志记录是非常重要的,可以帮助开发人员快速定位和解决问题。本文将介绍Spring Boot的日志配置详解,并提供两个示例。 Spring Boot的日志配置 Spring Boot的日志配置非常灵活,可以根据需要进行配置。在默认情况下,Spring Boot使用L…

    Java 2023年5月15日
    00
  • 一文带你掌握Java8中Lambda表达式 函数式接口及方法构造器数组的引用

    一文带你掌握Java8中Lambda表达式 函数式接口及方法构造器数组的引用 Lambda表达式 Lambda表达式是Java 8中引入的新特性之一,它是一个匿名函数,可以捕获参数并表现为一个代码块,而不像方法一样需要一个固定的名称。它主要用于传递行为或代码块以及事件处理等操作。 Lambda表达式的基本语法如下: (parameters) -> ex…

    Java 2023年5月26日
    00
  • 使用Java实现类似Comet风格的web app

    针对使用Java实现类似Comet风格的web app,我可以给您提供以下的攻略: 一、了解Comet Comet是一种Web服务器向浏览器发送异步数据的技术。在传统的Web应用程序中,客户端通过HTTP协议发起请求,服务器收到请求后即时返回响应。而Comet则是一种在Web服务器与浏览器之间建立持久连接的技术,使得服务端可以在有数据更新时主动向客户端推送数…

    Java 2023年5月19日
    00
  • Java使用wait/notify实现线程间通信上篇

    下面是详细讲解“Java使用wait/notify实现线程间通信上篇”的完整攻略。 标题 Java使用wait/notify实现线程间通信上篇 简介 线程间通信是多线程中非常重要的一个方面,它能够保证多个线程间能够相互协作,共同完成任务。Java中的wait/notify机制是线程间通信的一种重要实现方式。本文将介绍Java中的wait/notify机制的相…

    Java 2023年5月19日
    00
  • Java读写文件方法总结(推荐)

    Java读写文件方法总结(推荐) Java是一个非常强大的编程语言,用于读写文件时也同样灵活方便。下面是基于Java读写文件的方法总结。 读取文件 1. 使用InputStreamReader类 以下是使用InputStreamReader类读取文件的方法: public static void readWithInputStreamReader(Strin…

    Java 2023年5月20日
    00
  • 并发集合的作用是什么?

    并发集合是多线程编程中常见的数据结构,它可以解决多线程并发访问数据时的安全性问题,实现数据的共享与同步。下面是并发集合的作用和使用攻略的详细讲解。 并发集合的作用: 线程安全:并发集合能够保证多线程并发访问时的数据安全性,避免了多线程下数据出现冲突的情况。 高效性:并发集合能够提高多线程程序的运行效率,同时可以减少线程切换的次数,提高程序的吞吐量和响应能力。…

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