加油站模拟:如何模拟随机间隔的汽车?

时间:2010-10-28 14:11:16

标签: java multithreading time random simulation

作业如下:

  

加油站由2个泵组成。每个泵都有一定量的燃料可以分配。汽车随机到达,并尝试使用两个泵中的一个:

   - 如果有泵并且有燃料,则可立即允许汽车使用它。每辆车都需要一定量的燃料(随机数),并且必须等待与该燃料量成比例的时间。例如,一辆汽车可能需要6加仑并且将使用泵3秒,另一辆汽车可能需要10加仑并且将使用泵5秒等。当汽车加油时,它离开而另一辆车可以使用泵。在为汽车加油后,泵中的燃油量也会相应调整    - 如果当前正在使用两个泵,那么到达的汽车将等待,直到两个泵中的一个变为可用    - 如果泵的燃料耗尽,它必须等待油轮提供更​​多燃料。油轮定期到达(但不是经常),并将两个泵填满容量。当油轮为泵提供服务时,没有汽车可以使用泵。     忘记添加此

第一部分:您必须提交符合上述规格的详细设计。您的设计必须使用Java线程。您必须指定将使用的线程数量和类型,以及这些线程的同步方式。您可以用伪代码编写项目的这个阶段。这是为了帮助您了解各个部分将如何组合在一起。

第二部分:您必须使用Java线程和适当的同步方法提交完整的设计实现。必须根据上述规范仔细测试您的实施。


我想知道。如何使用Java Thread来模拟随机进入的汽车?
我很失落,并提前感谢你的帮助。

7 个答案:

答案 0 :(得分:12)

创建一个Car工厂类,该工厂类将一个Car添加到一个dequeue并随机进入休眠状态。

像所有学生一样,你可能会发现这个问题有点压倒性。如果你没有开始将它分解成你可以处理的较小块。想一想整体设计并开始实现它的一小部分。

例如,这是一个排队论问题。它们可能是汽车,银行行中的人,或与队列交互的任何东西。不要担心汽车或加油站的细节。这是你的问题:

  1. 你有一条线在一端添加新条目并在另一端带走它们。它被称为出列数据结构。阅读它。看看您是否可以编写(或重用)Java Dequeue类。完全理解它。写一个小驱动程序添加到一端并从另一端删除。
  2. 一旦你有了这个,你需要编写创建新条目的类来添加到dequeue而另一个删除它们。简单地通过编写以固定间隔工作的加法器/移除器来开始。您应该看到的是,如果加法器和移除器具有完全相同的接口,则排队等待的条目数不会改变。如果加法器的工作速度比去除器快,则该线应填满。如果卸妆工作速度比加法器快,那么您将永远不会有备份。确保您的简单类表现出这种行为。
  3. 添加随机位并开始模拟。您将希望了解行中的条目数量随时间的变化情况。
  4. 现在添加多行。您希望了解如何添加更多行来改变动态。

答案 1 :(得分:3)

如果您有固定的间隔,则在该间隔内到达的汽车数量为Poisson

两辆车之间的时间概率密度与exp(-t / tau)成正比,其中tau描述了汽车到达的频率。因此,您需要弄清楚如何创建指数分布的随机数。

根据概率密度p(t)= c * exp(-t / tau),我们整合了P(t)= 1-exp(-t / tau)的累积概率分布。因此,反转该函数得到t = -tau * ln(1-P(t))。因此,如果你生成一个在0和1之间均匀分布的数字u,你可以得到一个正确分布的t,因为t = -tau * ln(1-u)

答案 2 :(得分:1)

我可以看到你在哪里使用一个线程,但你真的不需要一个,除非这是一个图形模拟,你希望人们看到它实时运行。否则,只需跟踪时间表即可。在任何给定的时间点知道接下来会发生什么事件: A)卡车到达。 B)汽车到达。 C)汽车离开。

我想你会记录这些事情花了多长时间,所以简单地模拟事件发生得更快。每次有车到达时,新车到达的时间将是您决定的随机时间。

相信我,它会让你的生活变得更容易。

答案 3 :(得分:1)

首先,由于你的OP或问题陈述中没有任何内容表明系统是在挂钟上运行,所以不要假设它。任何基于睡眠的东西在创建汽车之间持续十秒都会让你在测试时发疯。创建一个简单的界面,为模拟提供时间并对其进行操作;如果您需要将它连接到挂钟,那么您可以,但您也可以像机器一样快地运行测试。

其次,通常最好将模拟作为事件运行 - 汽车到达车站,汽车从排队过渡到泵,汽车离开泵,油轮到达。通常基于时间的事件的优先级队列工作;当汽车开始填充时,您将完成其任务的事件添加到事件队列中,并在将来添加时间戳。如果在给定时间有油轮而不是处理线程优先级,那么编写逻辑不会处理汽车要容易得多。

由于你的任务要求你在线程之间展示一些同步,你可能想要运行汽车等待的过程,汽车加油/油轮卸载作为单独的线程(在真​​实软件中你不会,但更可能使用期货和执行程序,如果你想要并行执行,但我认为这是一个教学任务,你需要展示一些线程设计,而不是让图书馆为你排序所有。)

因此,对于每个时间片,您处理队列中的事件,等待所有事件处理完成,然后询问时钟以进行下一次滴答。快速时钟将立即返回下一秒的时间戳,或挂钟时钟​​将等到系统时间的下一秒。

由于您需要为每个任务使用线程,因此您需要在每个时间片的开始和结束时同步这些任务,并且您需要同步或以其他方式确保排队的事件在一段时间之前安全地排队并可见切片完成。

所以任务就像:

  • 来车

    • 每秒钟,确定到达的车数。这将是泊松分布。
    • 每次到达,发布一个汽车到达事件(或发布一个有汽车数量的事件)   (或者,使用其他一些随机机制;大多数其他方法只会导致一辆车一次到达,这对于放置在模型上通常不是一个有用的限制)
  • 来货油轮

    • 每个(油轮到达期)每个油泵到达油轮的事件
  • 等车

    • 增加等待汽车到达事件的汽车数量
    • 如果油轮已到达,请设置油轮等待标志
    • 如果泵是空的,那么
      • 如果油轮正在等待,将来重置油轮等待标志,填充泵,后泵无事件时间以填充泵
      • 如果泵有燃料并且任何汽车正在等待,减少汽车等待数量,将来的免费停车时间用于填充汽车

问题陈述尚不清楚油轮是否必须等待两个泵自由才能开始填充它们,在这种情况下你需要增加另一个“油罐就绪”状态。

如果任务在不同的线程中,则需要“手动”或使用java.util.concurrent.atomic中的原子值来同步各种计数器。

答案 4 :(得分:0)

您可以使用相同类型的汽车来源。您可以建立一些时间间隔,例如随机偏差。

答案 5 :(得分:0)

您可以使用线程安全的PriorityBlockingQueue来创建事件队列。

基本上,汽车到达,油罐车到达,汽车进入泵,以及离开泵的汽车都是事件。其中每个都有一个出现顺序,您为每个事件插入一个“事件”对象,并带有时间戳。您可以进行排列,以便PriorityBlockingQueue使用时间戳对事件进行排序。

最初,您为汽车到达生产者线程和油轮到达生产者线程启动一个线程。汽车到达线程将put()一个CarArrivalEvent发送到队列,然后休眠一段随机时间。油轮螺纹也是这样,但put() TankerArrivalEvent代替。

加油站有两个泵,每个泵由消费者线程代表。每个泵线程将take()一个CarArrivalEvent,然后休眠一段时间来填充汽车。你对TankerArrivalEvent做了类似的事情。

答案 6 :(得分:0)

不要使用泊松分布。 Poission将为您提供“在接下来的X分钟内到达的号码”。它不会给你“下次到达的时间”。

Wite a while while while like ::

  public int getTimeTillNextCar() {
    PROBABILITY = .001;
    int timeTillNextCar = 0;
    while(rand.nextDouble() > PROBABILITY) {
      timeTillNextCar++;
    }
  }

显然,我只是假设你正在使用谨慎的时间。但是,使用指数的单一绘制是可能的(并且有些人会更好)。这样会更有效率。但是,使用这种方法会使代码“混乱”,有些人可能不喜欢/理解。

记住,Poisson分布是通过计算当p非常小并且n中等大时给定n个绘制成功的伯努利数量而得出的。如果n“太大”,那么Possion分布将收敛到正态分布。

至于设计的其余部分......

Thread_A应该将汽车添加到队列中(确保使用线程安全队列类)

Thread_A shoule这样做:
加车,
睡眠(getTimeTillNextCar()),
加车,
睡眠(getTimeTillNextCar()),
加车,
睡眠(getTimeTillNextCar()),
等....

Thread_B和Thread_C应该将汽车从队列中取出:
Thread_B(和C)应该这样做:
get_car_off_queue,
睡眠(car.getFuelingTime(),
get_car_off_queue,
睡眠(car.getFuelingTime(), 等...