题目:设计一个Java程序,模拟一个简单的在线票务系统。要求如下:
- 创建一个
Ticket
类,包含票的编号和座位号。 - 在
Ticket
类中,提供一个构造方法来初始化票对象,并设置和获取票的属性。 - 创建一个
TicketSeller
类,用于模拟售票操作。TicketSeller
类应包含一个ArrayList
来存储可用的Ticket
对象,并提供同步的方法来创建、销售和取消销售票。 TicketSeller
类还应该有一个方法来计算当前可用和已售出的票数。- 在主类中,使用多线程模拟高并发购票场景,演示如何创建、销售和取消销售票,以及计算当前票数。
示例代码及解释:
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
// Ticket类定义
class Ticket {
private int id; // 票编号
private String seat; // 座位号
// Ticket类的构造方法
public Ticket(int id, String seat) {
this.id = id;
this.seat = seat;
}
// 设置和获取票编号的方法
public void setId(int id) {
this.id = id;
}
public int getId() {
return this.id;
}
// 设置和获取座位号的方法
public void setSeat(String seat) {
this.seat = seat;
}
public String getSeat() {
return this.seat;
}
}
// TicketSeller类定义
class TicketSeller {
private List<Ticket> availableTickets; // 可用的票
private List<Ticket> soldTickets; // 已售出的票
private Lock lock = new ReentrantLock(); // 锁,用于同步方法
// TicketSeller类的构造方法
public TicketSeller(int totalTickets) {
this.availableTickets = new ArrayList<>();
this.soldTickets = new ArrayList<>();
for (int i = 1; i <= totalTickets; i++) {
this.availableTickets.add(new Ticket(i, "Seat" + i));
}
}
// 创建票的方法(此方法不会在高并发环境下调用,仅用于初始化)
public void createTickets(int totalTickets) {
for (int i = 1; i <= totalTickets; i++) {
this.availableTickets.add(new Ticket(i, "Seat" + i));
}
}
// 销售票的方法
public void sellTicket(Ticket ticket) {
lock.lock(); // 获取锁
try {
if (availableTickets.contains(ticket)) {
availableTickets.remove(ticket);
soldTickets.add(ticket);
} else {
System.out.println("Ticket not available");
}
} finally {
lock.unlock(); // 释放锁
}
}
// 取消销售票的方法
public void cancelSale(Ticket ticket) {
lock.lock(); // 获取锁
try {
if (soldTickets.contains(ticket)) {
soldTickets.remove(ticket);
availableTickets.add(ticket);
} else {
System.out.println("Ticket was not sold");
}
} finally {
lock.unlock(); // 释放锁
}
}
// 计算当前可用和已售出的票数的方法
public int countAvailableTickets() {
return availableTickets.size();
}
public int countSoldTickets() {
return soldTickets.size();
}
}
// 主类
public class Main {
public static void main(String[] args) {
// 创建TicketSeller对象
TicketSeller ticketSeller = new TicketSeller(100);
// 创建多个线程模拟高并发购票场景
Thread t1 = new Thread(() -> {
for (int i = 1; i <= 10; i++) {
ticketSeller.sellTicket(ticketSeller.availableTickets.get(i));
}
});
Thread t2 = new Thread(() -> {
for (int i = 11; i <= 20; i++) {
ticketSeller.sellTicket(ticketSeller.availableTickets.get(i));
}
});
Thread t3 = new Thread(() -> {
for (int i = 21; i <= 30; i++) {
ticketSeller.cancelSale(ticketSeller.soldTickets.get(i - 11));
}
});
// 启动线程
t1.start();
t2.start();
t3.start();
// 等待线程完成
try {
t1.join();
t2.join();
t3.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 输出结果
System.out.println("Available tickets: " + ticketSeller.countAvailableTickets());
System.out.println("Sold tickets: " + ticketSeller.countSoldTickets());
}
}
解释:
- 我们首先定义了一个
Ticket
类,它有两个私有属性:id
(票编号)和seat
(座位号)。这个类提供了构造方法以及设置和获取这些属性的方法。 - 然后我们定义了一个
TicketSeller
类,它有两个ArrayList
类型的私有属性availableTickets
和soldTickets
,分别用于存储可用的和已售出的票。这个类提供了同步的方法来创建、销售和取消销售票,以及计算当前可用和已售出的票数。 - 在
Main
类的main
方法中,我们创建了一个TicketSeller
对象,并使用多线程模拟了高并发购票场景。我们创建了三个线程,分别用于销售、销售和取消销售票。我们使用了ReentrantLock
来确保在高并发环境下对票的操作是线程安全的。 - 最后,我们启动了线程并等待它们完成,然后输出了当前可用和已售出的票数。