Search code examples
javamultithreadingconcurrencysimulation

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


I have currently created classes such as CarPark, and Floor to represent the car park. I have used an ArrayList of the Floor class to show multiple levels in the car park.

I want to have multiple entries and exits on different floors, equipped with elevators to get from floor to floor.

How should I approach this? I want to be able to add and delete multiple vehicles to the car park when the vehicle enters and leaves at the same time.

How can I use threads and locks in this case?

============== Structure ============

public class CarPark{

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

}

Methods Implemented:

  • getFloorList() : ArrayList
  • getVehicleList(): ArrayList
  • getMostSuitableFloorForVehicle(Vehicle): Floor
  • addVehicle(Vehicle): void

  • getFreeSlots(): double

  • deleteVehicle(String): Vehicle

  • getVehiclePercentages(): HashMap<String, Double>

  • getOldestVehicle(): Vehicle

  • getLatestVehicle(): Vehicle

  • getVehicleById(String): Vehicle

  • getVehicleByDayYear(String, String): ArrayList

      public class Floor implements Comparable<Floor>{
    
      private double maxCapacity;
      private double currentCapacity;
      private int currentNumberOfVehicles;
      private ArrayList<Vehicle> vehicleList;
      private ArrayList<VehicleTypes> preferredVehicleType;
      private ArrayList<VehicleTypes> possibleVehicleType;
    

    }

Methods Implemented:

  • getCurrentNumberOfVehicles(): int
  • getCurrentCapacity(): double
  • getVehicleList(): ArrayList
  • getPreferredVehicleType(): ArrayList
  • getPossibleVehicleType(): ArrayList
  • getAvailableNumberOfSlots(): double
  • isParkingSlotsSufficient(Vehicle): boolean
  • addVehicle(Vehicle vehicle): void
  • getVehicleById(String): Vehicle
  • deleteVehicleByInstance(Vehicle): Vehicle
  • deleteVehicleByPlateId(String): Vehicle
  • toString(): String
  • compareTo(Floor): int

Rest are just vehicle classes that will be added to the car park.


Solution

  • The following mre uses two threads to simulate cars entering and cars leaving. You can control the rate by changing the SLEEP time:

    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{}
    

    The next enhancement is a car park Queue.
    Have a third thread push cars into the Queue (or multiple queses, one for each entrance, all filled by the same thread).
    Have simulateRandomEntries() pull from the queue (or queues) and push to a random floor.