Java 从多个队列中消费

Java 从多个队列中消费,java,concurrency,Java,Concurrency,我有大量的状态机。有时,状态机需要从一个状态移动到另一个状态,这可能是便宜的,也可能是昂贵的,并且可能涉及数据库读写等 这些状态更改是由于来自客户端的传入命令而发生的,并且可以随时发生 我想将工作量并行化。我想要一个队列,上面写着“将这台机器从这个状态移动到这个状态”。显然,任何一台机器的命令都需要按顺序执行,但是如果我有许多线程,我可以并行地向前移动许多机器 每个状态机可以有一个线程,但状态机的数量取决于数据,可能有数百或数千个线程;我不想要每个状态机都有一个专用线程,我想要某种类型的池 我如

我有大量的状态机。有时,状态机需要从一个状态移动到另一个状态,这可能是便宜的,也可能是昂贵的,并且可能涉及数据库读写等

这些状态更改是由于来自客户端的传入命令而发生的,并且可以随时发生

我想将工作量并行化。我想要一个队列,上面写着“将这台机器从这个状态移动到这个状态”。显然,任何一台机器的命令都需要按顺序执行,但是如果我有许多线程,我可以并行地向前移动许多机器

每个状态机可以有一个线程,但状态机的数量取决于数据,可能有数百或数千个线程;我不想要每个状态机都有一个专用线程,我想要某种类型的池

我如何拥有一个工作线程池,但确保严格按顺序处理每个状态机的命令


更新:假设
机器
实例有一个未完成命令列表。当线程池中的执行器使用完一个命令后,如果它有更多未执行的命令,它会将
机器
放回线程池的任务队列中。所以问题是,当您附加第一个命令时,如何自动地将
机器
放入线程池?并确保这一切都是线程安全的?

我建议您使用以下方案:

  • 创建线程池,可能是使用
    执行器的固定大小的线程池。newFixedThreadPool
  • 创建一些结构(可能是一个
    HashMap
    ),为每个状态机保存一个
    信号量。该信号量的值为1,并且将是公平的信号量以保持序列
  • 在Runnable中,它将在begging上执行此任务,只需为其状态机的信号量添加
    semaphore.aquire()
    ,并在run方法的末尾添加
    semaphore.release()

  • 通过线程池的大小,您可以控制并行级别。

    我建议您使用以下方案:

  • 创建线程池,可能是使用
    执行器的固定大小的线程池。newFixedThreadPool
  • 创建一些结构(可能是一个
    HashMap
    ),为每个状态机保存一个
    信号量。该信号量的值为1,并且将是公平的信号量以保持序列
  • 在Runnable中,它将在begging上执行此任务,只需为其状态机的信号量添加
    semaphore.aquire()
    ,并在run方法的末尾添加
    semaphore.release()

  • 通过线程池的大小,您可以控制并行度。

    我建议另一种方法。不要使用线程池来移动状态机中的状态,而是将线程池用于所有操作,包括执行工作。在完成导致状态更改的某些工作后,应将状态更改事件添加到队列中。处理状态更改后,应将另一个do work事件添加到队列中

    假设状态转换是工作驱动的,反之亦然,则不可能进行顺序处理

    将信号量存储在特殊映射中的想法是非常危险的。映射必须同步(添加/删除obj是线程不安全的),并且执行搜索(可能在映射上同步)然后使用信号量的开销相对较大


    此外,如果您想在应用程序中使用多线程体系结构,我认为您应该一直这样做。混合不同的体系结构可能会避免以后的麻烦。

    我建议另一种方法。不要使用线程池来移动状态机中的状态,而是将线程池用于所有操作,包括执行工作。在完成导致状态更改的某些工作后,应将状态更改事件添加到队列中。处理状态更改后,应将另一个do work事件添加到队列中

    假设状态转换是工作驱动的,反之亦然,则不可能进行顺序处理

    将信号量存储在特殊映射中的想法是非常危险的。映射必须同步(添加/删除obj是线程不安全的),并且执行搜索(可能在映射上同步)然后使用信号量的开销相对较大


    此外,如果您想在应用程序中使用多线程体系结构,我认为您应该一直这样做。混合使用不同的体系结构可以避免以后的麻烦。

    为每台机器提供一个线程ID。生成所需数量的线程。让所有线程贪婪地处理来自全局队列的消息。每个线程都将当前消息的服务器锁定为自己独占使用(直到它处理完当前消息及其队列上的所有消息为止),其他线程将该服务器的消息放在其内部队列上

    编辑:处理消息伪代码:

    void handle(message)
      targetMachine = message.targetMachine
      if (targetMachine.thread != null)
        targetMachine.thread.addToQueue(message);
      else
        targetMachine.thread = this;
        process(message);
        processAllQueueMessages();
        targetMachine.thread = null;
    
    处理消息Java代码:(我可能有点过于复杂,但这应该是线程安全的)


    每台机器有一个线程ID。生成所需数量的线程。让所有线程贪婪地处理来自全局队列的消息。每个线程都将当前消息的服务器锁定为自己独占使用(直到它处理完当前消息及其队列上的所有消息为止),其他线程将该服务器的消息放在其内部队列上

    编辑:处理消息伪代码:

    void handle(message)
      targetMachine = message.targetMachine
      if (targetMachine.thread != null)
        targetMachine.thread.addToQueue(message);
      else
        targetMachine.thread = this;
        process(message);
        processAllQueueMessages();
        targetMachine.thread = null;
    
    处理消息Java代码:(我可能有点过于复杂,但这应该是线程安全的)


    退房也许会有帮助,看看吧。也许会有帮助。这是一个非常正确的观点;抱歉,我不清楚,这些状态更改是外部触发的,我想在内部对它们进行排队;很抱歉,我不清楚,这些状态更改是从外部触发的,我想将它们排入队列