使用Java线程池,如何根据消息的特点,串行处理一些消息,并行处理其他消息?

使用Java线程池,如何根据消息的特点,串行处理一些消息,并行处理其他消息?,java,multithreading,Java,Multithreading,这更像是一个Java并发设计问题。我正在开发一个需要为许多不同客户机处理许多消息的应用程序。如果两条消息具有不同的客户端名称,则可以并行处理它们。但是,如果它们具有相同的客户机名称,则需要按顺序连续处理它们 实现这一点的最佳方式是什么 我当前的实现非常简单:我编写了一个名为OrderedExecutorPool的包装类。它有一个单线程执行器列表。在其提交方法中,它执行以下操作以确定将任务提交给哪个执行者: int executorNum = Math.abs(clientName.hashCod

这更像是一个Java并发设计问题。我正在开发一个需要为许多不同客户机处理许多消息的应用程序。如果两条消息具有不同的客户端名称,则可以并行处理它们。但是,如果它们具有相同的客户机名称,则需要按顺序连续处理它们

实现这一点的最佳方式是什么

我当前的实现非常简单:我编写了一个名为OrderedExecutorPool的包装类。它有一个单线程执行器列表。在其提交方法中,它执行以下操作以确定将任务提交给哪个执行者:

int executorNum = Math.abs(clientName.hashCode()) % numExecutors;
executorList.get(executorNum).submit(task);
这确保了具有相同客户端的所有消息都发送到相同的执行器,同时仍然支持并行处理不同客户端的消息

这种设计有几个问题:

1.)如果大多数客户端名称具有相同的哈希代码,则只有少数执行者在执行工作


2.)如果一个客户端有多条消息,则只有一个执行者可能无法跟上

有没有一个优雅的解决方案可以解决上述问题

编辑
clientName只是一个字符串。我只是在上面调用String.hashCode()方法

据我所知,没有jdk内置解决方案。我在当前的工作中使用这个基本逻辑实现了一个自定义执行器解决方案

  • 保留clientname到工作队列的内部映射(每个客户端都有自己的队列)
  • 当客户机有工作时,将其添加到他们的队列中
    • 如果这是队列上的第一个作业,请为此clientname/队列创建一个Runnable,并将其推入“真实”执行器(标准jdk线程池)
  • Runnable impl只使用单个客户端队列中的任务,直到为空,然后退出

这个简单的实现是“贪婪”方法(客户机将一直工作,直到其队列为空)。如果您的客户机比底层线程多,您可能需要一种更“公平”的方法,即客户机执行一定数量的任务,并在底层执行器中重新排队(从而允许其他客户机完成一些工作)。

您是否使用合理的方法重载哈希代码?它是否保证您总是为唯一字符串返回唯一值?您确定您的唯一客户机名称始终少于2^32(因此哈希代码)?您确定当前的hashCode实现是无冲突的吗?如果你对这些问题中的任何一个回答“不”。。。您犯了一个错误,应用程序将在某个时候崩溃/产生错误结果。“如果一个客户端有许多消息,那么只有一个执行者可能无法跟上”鉴于您对单个客户端进行串行处理的要求,唯一的选择是做更少的工作,或者提高效率。注意:Math.abs(Integer.MIN_VALUE)<0。您可以改用
。e、 g.
(clientName.hashCode()&Integer.MIN\u VALUE)%numExecutors或如果numExecutors是2的幂
clientName&(numExecutors-1)
@Specializet,如果两个不同的客户端名称产生相同的哈希代码,会发生什么?在我看来,他们的任务似乎总是提交给同一个单线程执行器服务。这将如何使应用程序崩溃?取决于实现。在大多数情况下,你会有一些严重的错误——所有这些错误几乎都无法追踪,除非你把事务和审计日志放在每件事上。