Java多线程模拟停车场多层多出入口车辆进出实现方案咨询
停车场并发功能设计实现方案
一、基础结构适配(泛型/出入口/电梯改造)
首先完成基础逻辑扩展,匹配需求:
- 泛型补全:原有
ArrayList全部补全对应泛型,比如CarPark的floorList定义为ArrayList<Floor>,Floor的vehicleList定义为ArrayList<Vehicle>,避免类型转换异常。 - 多出入口配置:在
Floor类新增两个集合属性List<Entrance> entrances、List<Exit> exits,存储当前楼层的出入口信息,Entrance/Exit类可扩展开放状态、排队长度、所属楼层等属性。 - 电梯功能实现:单独封装
ElevatorScheduler电梯调度器(单例模式,支持多台电梯并行调度),内部维护待处理请求队列,用独立线程异步处理不同楼层的车辆升降请求,车辆进出场需要使用电梯时,直接提交请求到调度队列即可。
二、并发安全实现(线程与锁机制)
原有代码使用的ArrayList、HashMap都是非线程安全类,多线程并发操作会出现并发修改异常、余位统计错误、同一车位重复分配等问题,需要从以下维度改造:
2.1 线程安全集合替换
所有集合类优先使用JUC包下的线程安全实现:
- 读多写少的列表(楼层列表、车辆列表、出入口列表)全部替换为
CopyOnWriteArrayList,无需额外加读锁即可保证并发读安全。 - 统计类
HashMap替换为ConcurrentHashMap,避免哈希表扩容、修改时的并发冲突。
2.2 细粒度锁设计
避免使用全局锁降低并发度,采用分层细粒度锁:
- 每个
Floor实例单独持有一个ReentrantLock锁,所有修改楼层数据的操作(新增/删除车辆、修改容量统计)都需要先获取当前楼层的锁,不同楼层的操作完全并行,大幅提升吞吐。 - 电梯调度器单独加锁,避免多楼层同时提交请求时的电梯状态冲突。
2.3 并发操作校验逻辑
为了避免读操作拿到的余位数据和加锁后的实际数据不一致,所有写操作需要做二次校验:
- 车辆进场:先无锁查询匹配的目标楼层,获取目标楼层锁后,再次调用
isParkingSlotsSufficient校验余位,校验通过再执行新增操作,最后释放锁。 - 车辆出场:先无锁查询车辆所在楼层,获取对应楼层锁后,二次校验车辆确实在当前楼层的车辆列表中,再执行删除操作,最后释放锁。
三、核心代码改造示例
改造后的Floor类(加锁+线程安全集合)
public class Floor implements Comparable<Floor>{ // 楼层级细粒度锁 private final ReentrantLock floorLock = new ReentrantLock(); private double maxCapacity; private double currentCapacity; private int currentNumberOfVehicles; // 替换为线程安全集合并补全泛型 private CopyOnWriteArrayList<Vehicle> vehicleList; private CopyOnWriteArrayList<VehicleTypes> preferredVehicleType; private CopyOnWriteArrayList<VehicleTypes> possibleVehicleType; private CopyOnWriteArrayList<Entrance> entrances; private CopyOnWriteArrayList<Exit> exits; private int floorNum; // 改造新增车辆方法,加锁保证原子性 public boolean addVehicle(Vehicle vehicle) { floorLock.lock(); try { // 二次校验余位 if (!isParkingSlotsSufficient(vehicle)) { return false; } vehicleList.add(vehicle); // 同步更新容量统计 currentCapacity += vehicle.getOccupiedSpace(); currentNumberOfVehicles++; vehicle.setParkedFloor(this); return true; } finally { // 确保锁一定会释放 floorLock.unlock(); } } // 改造删除车辆方法 public Vehicle deleteVehicleByPlateId(String plateId) { floorLock.lock(); try { Vehicle target = getVehicleById(plateId); if (target == null) { return null; } vehicleList.remove(target); currentCapacity -= target.getOccupiedSpace(); currentNumberOfVehicles--; return target; } finally { floorLock.unlock(); } } // 其余原有方法无需大幅调整,所有修改类属性的方法都按照上述逻辑加锁即可 }
改造后的CarPark类(支持并发操作+电梯调度)
public class CarPark{ // 替换为线程安全集合并补全泛型 private CopyOnWriteArrayList<Floor> floorList; private CopyOnWriteArrayList<Vehicle> vehicleList; // 电梯调度器单例 private final ElevatorScheduler elevatorScheduler = ElevatorScheduler.getInstance(); // 改造车辆进场方法 public boolean addVehicle(Vehicle vehicle) { Floor targetFloor = getMostSuitableFloorForVehicle(vehicle); if (targetFloor == null) { return false; } // 调用楼层加锁的新增方法 boolean addSuccess = targetFloor.addVehicle(vehicle); if (addSuccess) { vehicleList.add(vehicle); // 提交电梯调度请求,异步执行 elevatorScheduler.submitRequest(new ElevatorRequest(vehicle, 1, targetFloor.getFloorNum())); } return addSuccess; } // 改造车辆出场方法 public Vehicle deleteVehicle(String plateId) { Vehicle target = getVehicleById(plateId); if (target == null) { return null; } Floor parkedFloor = target.getParkedFloor(); Vehicle deleted = parkedFloor.deleteVehicleByPlateId(plateId); if (deleted != null) { vehicleList.remove(deleted); elevatorScheduler.submitRequest(new ElevatorRequest(deleted, parkedFloor.getFloorNum(), 1)); } return deleted; } // 其余原有统计方法都是读操作,使用线程安全集合无需额外加锁即可直接使用 }
内容的提问来源于stack exchange,提问作者Imperial_J
相关产品推荐
相关产品推荐

