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

     2023-02-16     178

关键词:

【中文标题】使用多线程在 Java 中模拟停车场中的多个入口和出口【英文标题】:Simulating Multple Entries and Exits in a Vehicle Car Park in Java with Multi Threading 【发布时间】:2022-01-09 13:40:42 【问题描述】:

我目前创建了 CarPark 和 Floor 等类来表示停车场。我使用了 Floor 类的 ArrayList 来显示停车场的多个楼层。

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

我应该如何处理这个问题?我希望能够在车辆同时进入和离开时向停车场添加和删除多辆车辆。

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

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

public class CarPark

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


实现的方法:

getFloorList() : ArrayList getVehicleList(): ArrayList getMostSuitableFloorForVehicle(Vehicle): 楼层

addVehicle(Vehicle): 无效

getFreeSlots(): 双倍

deleteVehicle(String): 车辆

getVehiclePercentages(): HashMap

getOldestVehicle(): 车辆

getLatestVehicle(): 车辆

getVehicleById(String): 车辆

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;

实现的方法:

getCurrentNumberOfVehicles(): int getCurrentCapacity(): 双倍 getVehicleList(): ArrayList getPreferredVehicleType(): ArrayList getPossibleVehicleType(): ArrayList getAvailableNumberOfSlots(): 双倍 isParkingSlotsSufficient(Vehicle): 布尔值 addVehicle(Vehicle 车辆): void getVehicleById(String): 车辆 deleteVehicleByInstance(Vehicle): 车辆 deleteVehicleByPlateId(String): 车辆 toString(): 字符串 compareTo(Floor): int

其余只是将添加到停车场的车辆类别。

【问题讨论】:

我添加了一个概述,代码很长 请注意,Stack Overflow 是一个 Q/A 平台,您可以在其中展示具体代码并描述您尝试过的内容以及实际结果与您的预期有何不同,或者提出其他具体问题。它不是一个让其他人免费为你完成整个工作或家庭作业的平台。 【参考方案1】:

下面的 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() 从队列(或多个队列)中拉出并推送到随机楼层。

【讨论】:

哇!这是一个好方法......我只有一件小事要问,之后这将是完美的答案。现在假设我们在停车场有 6 个入口和 6 个出口。我是否应该使用线程池并运行模拟随机条目() 6 次来模拟多个条目。并使用停车场中的同步列表来跟踪车辆 ID,然后还运行 6 次模拟随机退出()来模拟系统中的 6 个出口?我也会尝试使用非常实用的队列。 另外只需确保一件事,使每个方法同步会在这里提供任何优势吗?在我修改同步列表的任何地方都需要使用它吗? 查看我的编辑:我会为每个任务使用一个线程:一个用于将车辆推入入口队列,一个用于将车辆推到地板上,一个用于将车辆推到随机出口。跨度> 旁注:您打算可视化停车场模拟吗?如果是,您打算使用哪些工具(swing?JavaFX?) 您使用了同步列表,但您忘记了同步()它们。否则它们不是线程安全的(除非这是问题的意图)。【参考方案2】:

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

在 Java 中,您可以使用添加到 Thread 的 Runnable 来运行模拟循环。

这是一个例子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 小时时段。一种可能的模拟可能是:

前两个小时有汽车进入停车场。 汽车在接下来的八小时内进出停车场。 汽车在过去两个小时内离开停车场。

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

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

现在您所要做的就是确定每小时有多少汽车进入停车场,以及每小时有多少汽车离开停车场。价格应该非常接近。

每小时进入停车场的汽车太多会填满停车场。

每小时进入停车场的车辆太少,停车场大部分都是空的。

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

【讨论】:

那么我怎样才能一次将多辆车添加到停车场。我不应该选择一种使用并发循环的方法吗?如果我想将多个项目添加到多个数组列表中,如何在这里实现? @L_Jay:“更新模拟模型”注释是您添加和删除车辆的地方。我建议随机添加和移除车辆,因此添加车辆之间的时间不是恒定的,但您仍然可以预测一段时间内添加的车辆数量。一个主游戏循环可以避免很多并发问题。 当我启动线程时,这是否会一次添加多辆汽车,因为这是一个正常的 for 循环?另外在添加多辆汽车时,我应该在添加车辆时使用锁来锁定地板对象吗? @L_Jay:让我们算一下。您尝试每 200 毫秒创建 5 辆汽车。但是,由于Random,您只有 10%(十分之一)的机会制造汽车。因此,平均而言,您每 200 毫秒制造 1/2 辆汽车,或每秒(分钟)制造 2 1/2 辆汽车。相同的数学运算适用于 remove car 循环。您可以调整循环限制和/或创建/移除汽车的概率。对于汽车创建循环和汽车移除循环,我会保持数学相同。代码中的任何地方都不需要锁。 我明白了,这完全有道理。但我想使用线程和并发,这是我的主要意图。我想要一些指示,请......

java多线程详解

...情:1、java.lang.Thread类的一个实例;2、线程的执行。 使用java.lang.Thread类或者java.lang.Runnable接口编写代码来定义、实例化和启动新线程。 一个Thread类实例只是一个对象,像Java中的任何其他对象一样,具有变量和方法,生... 查看详情

java线程及多线程技术及应用

1线程基本概念1、进程和线程的基础知识 进程:运行中的应用程序称为进程,拥有系统资源(cpu、内存) 线程:进程中的一段代码,一个进程中可以哦有多段代码。本身不拥有资源(共享所在进程的资源)   &... 查看详情

java多线程基础

...本身依靠程序进行运行线程是程序中的顺序控制流,只能使用分配给程序的资源和环境2进程:执行中的程序一个进程至少包含一个线程3单线程:程序中只存在一个线程,实际上主方法就是一个主线程4多线程:在一个程序中运行... 查看详情

java线程详解

...情:1、java.lang.Thread类的一个实例;2、线程的执行。 使用java.lang.Thread类或者java.lang.Runnable接口编写代码来定义、实例化和启动新线程。 一个Thread类实例只是一个对象,像Java中的任何其他对象一样,具有变量和方法,生... 查看详情

JAVA - 如何在 NIO 服务器中的多个线程之间共享对象(文件和数组列表)

...nanNIOserver【发布时间】:2014-01-0217:32:43【问题描述】:我使用RoxJavaNIO教程改编并创建了一个多线程TCP服务器(http://rox-xmlrpc.sourceforge.net/nio 查看详情

java使用栈和队列模拟停车场问题

停车场管理:本题为计算机系专业课数据结构实验[问题描述]设停车场是一个可以停放n辆汽车的狭长通道,且只有一个大门可供汽车进出。汽车在停车场内按车辆到达时间的先后顺序,依次有北向南排列(大门在最南端,最先到... 查看详情

java之线程

...Java线程的实现 一种是实现Runnable接口 一种是继承Thread类 使用线程来控制plane.jpg图片的移动im 查看详情

[java并发基础]也来聊聊java多线程中的一些概念问题

文章导航什么是多线程并发为什么要进行多线程并发编程线程安全Java内存模型映射到现代硬件架构内存可见性问题的解决方案synchronizedvolatile原子性和线程安全,锁和内存可见性什么是多线程并发理清并发和并行的概念。并... 查看详情

多线程

1.线程的概念:多线程使得程序中的多个任务可以同时执行。Java的重要功能之一就是内部支持多线程,在一个程序中运行同时运行多个任务。线程:一个程序可能包含多个同时运行的任务。线程是指一个任务从头至尾的执行流程... 查看详情

java面试之多线程

一、线程和进程之间的区别1.进程:一个在内存中运行的应用程序。每个进程都有自己独立的一块内存空间,一个进程可以有多个线程,比如在Windows系统中,一个运行的xx.exe就是一个进程。进程中的一个执行任务(控制单元),... 查看详情

java中啥叫做线程?啥叫多线程?多线程的特点是啥

...成多项任务,不是为了提高运行效率,而是为了提高资源使用效率来提高系统的效率。线程是在同一时间需要完成多项任务的时候实现的。多线程的优点:使用线程可以把占据长时间的程序中的任务放到后台去处理用户界面可以... 查看详情

java多线程原理及thread类的使用

...为了解决多部分代码同时执行。6.多线程的优点是合理的使用资源。二、jvm中的多线程1.jvm中的多线程有很多,其中有负责定义代码运行的线程(这个从main方法 查看详情

多线程学习----createthread

...pp:定义控制台应用程序的入口点。 同一进程中的多个线程将共享该进程中的全部系统资源,如虚拟地址空间、文件描述符和信号处理等,但是同一个进程中的多个线程都有各自的调用栈、寄存器环境和线程本地存储。线程都... 查看详情

java线程学习。

一、操作系统中线程和进程的概念现在的操作系统是多任务操作系统。多线程是实现多任务的一种方式。进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程。比如在Window... 查看详情

什么是java多线程编程?

一、什么是多线程:我们现在所使用操作系统都是多任务操作系统(早期使用的DOS操作系统为单任务操作系统),多任务操作指在同一时刻可以同时做多件事(可以同时执行多个程序)。多进程:每个程序都是一个进程,在操作系统中... 查看详情

多线程 Java 应用程序中的 SQLite

】多线程Java应用程序中的SQLite【英文标题】:SQLiteinamultithreadedjavaapplication【发布时间】:2012-05-2906:18:41【问题描述】:我编写了一个java应用程序,它偶尔将事件从多个线程记录到SQLite数据库。我注意到我可以通过同时产生少量... 查看详情

java线程

...程中执行运算的最小单位,亦是调度运行的基本单位。2.使用多线程在Java的JDK开发包中,已经自带了对多线程技术的支持,可以很方便地进行多线程编程。实现多线程编程的方式有两种,一种是继承Thread类,另一种是实现Runnable... 查看详情

java入门系列-21-多线程

...工作。多个线程交替占用CPU资源,并非真正的并行执行。使用多线程能充分利用CPU的资源,简化编程模型 查看详情