写出java代码并给出注释,并对每行代码进行说明:现有一个在线售票系统,总共有200张票,假设4个线程同时订票,网络传输延时为5毫秒,试编写程序模拟12306的售票过程。 进阶设计:试考虑同步机制。
时间: 2024-02-20 08:01:53 浏览: 76
以下是Java代码及注释:
```java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class OnlineTicketSystem {
private static int totalTicket = 200; // 初始化总票数为200张
private static Object lock = new Object(); // 定义一个锁对象
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(4); // 创建一个线程池,最多同时执行4个线程
for (int i = 1; i <= 4; i++) {
executorService.execute(new TicketRunnable(i)); // 添加4个线程,每个线程都是TicketRunnable的实例
}
executorService.shutdown(); // 关闭线程池
}
static class TicketRunnable implements Runnable {
private int threadId; // 线程ID
public TicketRunnable(int threadId) {
this.threadId = threadId;
}
@Override
public void run() {
while (true) { // 线程一直执行,直到订票成功或票已售完
synchronized (lock) { // 加锁
if (totalTicket > 0) { // 判断是否有票
try {
Thread.sleep(5); // 模拟网络传输延时
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread " + threadId + " booked ticket " + totalTicket); // 输出订票信息
totalTicket--; // 更新剩余票数
} else {
System.out.println("Thread " + threadId + " failed to book ticket."); // 输出订票失败信息
break; // 退出循环,结束线程
}
}
}
}
}
}
```
每行代码的说明如下:
1. `import java.util.concurrent.ExecutorService;` 导入Java中用于执行多线程任务的ExecutorService接口。
2. `import java.util.concurrent.Executors;` 导入Java中用于创建线程池的Executors类。
3. `public class OnlineTicketSystem {` 声明一个名为OnlineTicketSystem的公共类。
4. `private static int totalTicket = 200;` 声明一个静态的总票数变量,初始化为200。
5. `private static Object lock = new Object();` 声明一个静态的Object类型的锁对象。
6. `public static void main(String[] args) {` 程序的主方法。
7. `ExecutorService executorService = Executors.newFixedThreadPool(4);` 创建一个最多同时执行4个线程的线程池。
8. `for (int i = 1; i <= 4; i++) {` 创建4个线程。
9. `executorService.execute(new TicketRunnable(i));` 添加一个TicketRunnable的实例到线程池中。
10. `executorService.shutdown();` 关闭线程池。
11. `static class TicketRunnable implements Runnable {` 声明一个静态的内部类TicketRunnable,实现了Runnable接口。
12. `private int threadId;` 声明一个线程ID变量。
13. `public TicketRunnable(int threadId) {` 构造函数,用于初始化线程ID。
14. `this.threadId = threadId;` 将构造函数中传入的线程ID赋值给变量threadId。
15. `@Override` 标识该方法是覆盖了父类或接口的方法。
16. `public void run() {` 实现Runnable接口中的方法。
17. `while (true) {` 循环执行,直到订票成功或票已售完。
18. `synchronized (lock) {` 加锁,防止多个线程同时访问共享资源。
19. `if (totalTicket > 0) {` 判断是否还有票。
20. `Thread.sleep(5);` 线程休眠5毫秒,模拟网络传输延时。
21. `System.out.println("Thread " + threadId + " booked ticket " + totalTicket);` 输出订票信息。
22. `totalTicket--;` 更新剩余票数。
23. `} else {` 如果已经没有票了。
24. `System.out.println("Thread " + threadId + " failed to book ticket.");` 输出订票失败信息。
25. `break;` 跳出循环,结束线程。
26. `}`
27. `}`
28. `}`
29. `}`
同步机制的实现:在访问共享资源(totalTicket)前加锁,确保每个线程都能独占访问,避免多个线程同时访问共享资源导致数据不一致的问题。在访问完共享资源后解锁,让其他线程可以访问该资源。在代码中,使用了synchronized关键字来实现同步。由于使用了锁,因此每次只有一个线程可以访问totalTicket变量,从而实现了同步访问。
阅读全文