【问题标题】:Gas Station Simulation: How to simulate Cars coming at random intervals?加油站模拟:如何模拟随机间隔的汽车?
【发布时间】:2011-05-01 22:01:59
【问题描述】:

作业如下:

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

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

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

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


我想知道。如何使用 Java 线程来模拟随机进入的汽车?
我很迷茫,提前感谢您的帮助。

【问题讨论】:

  • 是否需要使用多个线程?我不认为这是使用线程的好情况,但是如果目标是学习使用线程,那么这种批评当然不适用。
  • 是的,我想我需要使用多个线程。
  • 是的,我同意,线程的情况不是很好。但那只是为了学习。
  • 和我成绩的很大一部分。哈哈

标签: java multithreading time random simulation


【解决方案1】:

创建一个 Car 工厂类,该类吐出要添加到出队的 Car 并随机休眠一段时间。

像所有学生一样,您可能会发现这个问题有点难以解决。如果你不开始把它分解成你可以处理的更小的块。考虑一个整体设计并开始实施它的小部分。

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

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

【讨论】:

  • 1000 不是随机的;每秒一个。
  • 我可以做 Random r = new Random(); Thread.currentThread().sleep(r.nextInt(100000))
  • @Luron 是的,你可以这样做,你也可以睡一个固定的时间并随机检查以决定是否创建一辆新车,即。 if (new Random.nextInt(100)
  • @Luron - 从简单开始并增加复杂性。如果你被允许使用 Java 内置集合,我会从这个开始:download.oracle.com/javase/6/docs/api/java/util/concurrent/…。仔细研究一下 BlockingDequeue。完全理解它;尝试一些简单的问题;谷歌搜索一些例子。你在学习;慢慢开始,随着你的了解加快。
  • 你不需要双端队列;一个简单的队列就足够了。 (您只会在一端添加并在另一端移除。)
【解决方案2】:

如果您有固定的间隔,则在该间隔内到达的汽车数量为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)

【讨论】:

  • 泊松分布绝对是你想要的。
  • 泊松分布与解决 OP 问题有何关系?即How can I use a Java Thread to simulate the cars coming in at random intervals?
  • 对于课堂练习,我将从使用Random 的均匀分布开始生成数字。一旦这工作了,就去泊松来获得额外的学分。
  • 这无济于事 a)它不满足要求 b)它为新手增加了巨大的复杂性。
  • 我不认为这是问题的具体内容 - 它似乎比要求的要复杂得多
【解决方案3】:

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

我想您正在跟踪这些事情需要多长时间,因此只需模拟事件以使其更快发生。每次一辆车到货,新车到货所需的时间将是由您决定的随机时间。

相信我,简单的事情会让你的生活变得更轻松。

【讨论】:

  • 忘记添加此**第一部分:您必须提交符合上述规格的详细设计。您的设计必须使用 Java 线程。 您必须指定将使用的线程数量和类型,以及这些线程将如何同步。您可以用伪代码编写项目的这个阶段。这是为了帮助您了解各个部分如何组合在一起。 ** 第二部分:您必须使用 Java 线程和适当的同步方法提交您的设计的完整实现。您的实现必须根据上述规范仔细测试。
  • 好吧,如果这是一个使用 Java 线程的练习,你应该这样做。但是,要知道这对于任何实际上下文中的线程来说都不合适。
【解决方案4】:

首先,由于您的 OP 和问题陈述中没有任何内容表明系统正在按时运行,因此不要假设它确实如此。任何基于在制造汽车之间睡十秒钟的东西都会让你在测试时发疯。创建一个简单的界面,为模拟提供时间并与之对抗;如果您需要将其与挂钟绑定,那么您可以,但您也可以尽可能快地运行测试。

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

由于您的任务要求您演示线程之间的一些同步,您可能希望将汽车等待、汽车加油/油罐车卸载作为单独的线程运行(在实际软件中您不会,但更可能使用期货和executor 如果你想要并行执行,但我假设这是一个教学任务,你需要展示一些线程设计,而不是让库为你整理出来)。

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

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

所以任务是这样的:

  • 来车

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

    • 每个(油轮到达周期)发布一个油轮到达事件每个泵
  • 等车

    • 增加等待汽车到达事件的汽车数量
    • 如果油轮到达,设置油轮等待标志
    • 如果泵空闲,则
      • 如果油轮正在等待,请重置油轮等待标志、填充泵、为将来的填充泵时间发布无泵事件
      • 如果泵有燃料并且有任何汽车正在等待,则减少等待的汽车计数,然后发布无泵事件以供未来加油时间

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

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

【讨论】:

    【解决方案5】:

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

    【讨论】:

      【解决方案6】:

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

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

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

      加油站有两个泵,每个泵都由消费者线程表示。每个泵线程将take() CarArrivalEvent,然后休眠填充汽车所需的时间。您对 TankerArrivalEvent 执行类似操作。

      【讨论】:

        【解决方案7】:

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

        像这样写一个小的while循环::

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

        显然,我只是假设您正在使用谨慎的时间。但是,有可能(有些人会认为更好)从指数中使用单次平局。这样会更有效率。但是,使用这种方法会使代码变得“数学”,有些人可能不喜欢/不理解。

        请记住,泊松分布是通过计算当 p 非常小而 n 中等大时 n 次平局成功的伯努利平局得出的。如果 n “太大”,则 Possion 分布将收敛到正态分布。

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

        Thread_A 应该将汽车添加到队列中(一定要使用线程安全的队列类)

        Thread_A 应该这样做:
        添加汽车,
        睡眠(getTimeTillNextCar()),
        添加汽车,
        睡眠(getTimeTillNextCar()),
        添加汽车,
        睡眠(getTimeTillNextCar()),
        等等……

        Thread_B 和 Thread_C 应该让汽车离开队列:
        Thread_B(和 C)应该这样做:
        get_car_off_queue,
        睡眠(car.getFuelingTime(),
        get_car_off_queue,
        睡眠(car.getFuelingTime(), 等等……

        【讨论】:

        • 如果你有两个线程代表泵,那么它不符合问题规范 - 问题说“如果泵可用并且有燃料,汽车就可以立即使用它” .如果您没有在 RTOS 中运行,则无法保证空闲泵的线程将被调度并让汽车出队。
        • @Pete -- 没错,但这是一个很容易解决的问题。处理“无队列”的情况不会破坏这个常规设置。
        猜你喜欢
        • 2012-11-09
        • 1970-01-01
        • 2020-01-23
        • 1970-01-01
        • 1970-01-01
        • 2011-01-04
        • 1970-01-01
        • 2021-11-16
        • 2020-07-17
        相关资源
        最近更新 更多