使用多线程在 Java 中模拟停车场中的多个入口和出口

Simulating Multple Entries and Exits in a Vehicle Car Park in Java with Multi Threading

我目前已经创建了 class 实体,例如 CarPark 和 Floor 来表示停车场。我使用了楼层的 ArrayList class 来显示停车场中的多个级别。

我想在不同的楼层有多个入口和出口,配备电梯从一层到另一层。

我应该如何处理这个问题?我希望能够在车辆同时进出时,对停车场添加和删除多辆车

在这种情况下如何使用线程和锁?

==============结构============

public class CarPark{

private ArrayList<Floor> floorList;
private ArrayList<Vehicle> vehicleList;

}

实施的方法:

实施的方法:

其余车辆 class 将添加到停车场。

任何模拟或游戏的基础都是 game loop。这是一个 运行 持续一段时间的循环。

在Java中,你可以使用一个Runnable added to a Thread到运行一个模拟循环。

这是一个例子Runnable

public class SimulationRunnable implements Runnable {
    
    /** Simulation run time, in minutes */
    private final int duration;
    
    private final Random random;
    
    private final SimulationView view;
    
    private final SimulationModel model;
    
    public SimulationRunnable(SimulationView view, SimulationModel model, 
            int duration) {
        this.view = view;
        this.model = model;
        this.duration = duration;
        this.random = new Random();
    }

    @Override
    public void run() {
        int iterations = duration * 60 * 5;
        
        for (int index = 0; index < iterations; index++) {
            // Update simulation model
            
            // We will add cars for the first 10 hours (minutes)
            
            if (index < iterations - 600) {
                for (int jndex = 0; jndex < 5; jndex++) {
                    if (random.nextInt(10) == 5) {
                        // Add car
                    }
                }
            }
            
            // We will remove cars for the last 10 hours (minutee)
            
            if (index > 600) {
                for (int jndex = 0; jndex < 5; jndex++) {
                    if (random.nextInt(10) == 3) {
                        // Remove car
                    }
                }
            }
            
            // Report status every 300 iterations
            if (index % 300 == 0) {
                
            }
            
            // Pause simulation loop
            try {
                Thread.sleep(200L);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    
}

要开始模拟,您使用 Runnable 创建一个 Thread

new Thread(new SimulationRunnable(view, model, 12)).start();

假设您要模拟汽车进出停车场的 12 小时时间段。一种可能的模拟可能是:

  • 汽车在前两个小时进入停车场。
  • 汽车在接下来的八小时内进出停车场。
  • 汽车在最后两个小时离开停车场。

我们还假设模拟计时器 运行s 为一分钟代表一小时。所以模拟会运行 12分钟。

我们还假设模拟循环 运行 每秒五次。这意味着模拟循环将每 200 毫秒执行一次,总共执行 3,600 次。

现在你所要做的就是决定每小时有多少辆车进入停车场以及有多少辆车离开停车场。利率应该非常接近。

每小时进入停车场的车辆太多,停车场会被填满。

每小时进入停车场的车辆太少会使停车场大部分空无一人。

游戏循环将更新您的模拟模型。每隔一段时间,比如每场比赛一小时(分钟)您报告停车场的状态。

下面的mre是用两个线程模拟车进车出。您可以通过更改 SLEEP 时间来控制速率:

import java.util.*;

public class CarPark {

    private static final int NUM_OF_FLOOORS = 4, SLEEP = 3000;
    private final List<Floor> floorList;

    public CarPark() {
        floorList = Collections.synchronizedList(new ArrayList<>());
        for(int i=0; i < NUM_OF_FLOOORS; i++){
            floorList.add(new Floor(i));
        }
    }

    private Floor getRandomFloor() {
        Collections.shuffle(floorList);
        return floorList.get(0);
    }

    void simulateRandomTraffic(){
        simulateRandomEntries();
        simulateRandomExits();
    }

    void simulateRandomEntries(){
        new Thread(()->{
            while(true){
                getRandomFloor().addVehicle(new Vehicle());
                try {
                    Thread.sleep(SLEEP);
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }
            }
        }).start();
    }

    void simulateRandomExits(){
        new Thread(()->{
            while(true){
                getRandomFloor().removeRandomVehicle();
                try {
                    Thread.sleep(SLEEP);
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }
            }
        }).start();
    }

    public static void main(String[] args) {
        new CarPark().simulateRandomTraffic();
    }
}

class Floor{

    private final double maxCapacity = 100;
    private final List<Vehicle> vehicleList;
    private final int floorNumber;

    public Floor(int floorNumber) {
        this.floorNumber = floorNumber;
        vehicleList = Collections.synchronizedList(new ArrayList<>());
    }

    public int getCurrentNumberOfVehicles() {
        return vehicleList.size();
    }

    public boolean isFull(){
        return maxCapacity <= getCurrentNumberOfVehicles();
    }

    public boolean isEmpty(){
        return  getCurrentNumberOfVehicles() <= 0;
    }

    public int getFloorNumber() {
        return floorNumber;
    }

    private Vehicle getRandomVehicle() {
        Collections.shuffle(vehicleList);
        return vehicleList.get(0);
    }

    public boolean removeRandomVehicle(){
        if(isEmpty()) {
            System.err.println("Floor "+ getFloorNumber()+" is empty. Can't remove vehicle");
            return false;
        }
        return removeVehicle(getRandomVehicle());
    }

    public boolean addVehicle(Vehicle v){
        if(isFull()) {
            System.err.println("Floor "+ getFloorNumber()+" is full. Can't add vehicle");
            return false;
        }
        vehicleList.add(v);
        System.out.println("Floor "+ getFloorNumber()+" vehicle added ("+ getCurrentNumberOfVehicles()+"/"+maxCapacity+")");
        return true;
    }

    public boolean removeVehicle(Vehicle v){
        if(isEmpty()) {
            System.err.println("Floor "+ getFloorNumber()+" is empty. Can't remove vehicle");
            return false;
        }
        vehicleList.remove(v);
        System.out.println("Floor "+ getFloorNumber()+" vehicle removed ("+ getCurrentNumberOfVehicles()+"/"+maxCapacity+")");
        return true;
    }
}

class Vehicle{}

下一个改进是停车场 Queue
让第三个线程将汽车推入 Queue(或多个问题,每个入口一个,全部由同一个线程填充)。
simulateRandomEntries() 从队列中拉出并推送到随机楼层。