【问题标题】:Design pattern for multithreaded java application多线程Java应用程序的设计模式
【发布时间】:2017-07-13 19:43:13
【问题描述】:

我有一个接收函数请求的后端

update(by_whom, payload);

然后我处理请求,并相应地回答。

每次用户发送请求,消息都会经过多个处理对象,然后才会产生答案。

现在,我将如何处理每个用户在他自己的线程中?我不明白如何将事件分派到定制线程。

示例:

User 1 发送第一个请求 -> 我们创建一个 ThreadUser1 并在那里处理它。

User 2 发送第一个请求 -> 我们创建一个 ThreadUser2 并在那里处理它,如果来自 user1 的 request1 没有完成,它们可以一起运行。

User 1 发送第二个请求,他发送的第一个还没有完成 -> 我们在 threadUser1 上分发这个请求,因此它会等待 request1 完成。

基本上,在收到请求后,它应该只放在同一用户发送的请求后面的队列中,并与其他所有请求同时运行。

我认为可行的方法:

我考虑将每个请求从主线程发布到并发列表中,并让线程检查该列表(如果为真),然后从它们所属的用户那里挑选请求。

这有几个问题: - 每次我都需要检查整个列表以查找正确用户的请求。

  • 这假设我已经为每个可能的用户运行了一个线程,但我没有,我只知道用户第一次发短信时的 id。

  • 效率,可能有大量循环一遍又一遍地检查同一个列表。

  • 线程应该在该用户的所有请求完成后停止

关于最后一点:这是因为我需要有一个限制 MAX 在我们已经有 MAX 个线程运行时收到的任何请求,这些新请求不属于任何当前用户(aka running thread)都会正常处理(在主线程中排队,一个接一个)。

我真的不知道该怎么做,如果有人能指出我正确的方向,我会很高兴。

【问题讨论】:

  • 有一张地图user -> tasks。当请求进入时,将任务列表添加到该映射并安排工作线程在此列表上工作 - 如果同时有来自同一用户的另一个请求到达,您将找到它的列表,您可以简单地添加到该列表中。让服务器控制对地图的访问,即每个工作人员都必须通知其完成以让服务器清理(或重新安排)。然后让列表(例如queue)同步 s.t.线程可以异步地从中拉取新调度的请求。
  • 如果我理解正确,您在线程之间没有任何共享状态,您可以使用每个线程的队列来保持请求与一个线程相关联。要处理“最大”数量的线程,我建议使用 FixedThreadPool(请参阅Executors.newFixedThreadPooldocs.oracle.com/javase/7/docs/api/java/util/concurrent/…)?如有必要,我可以写一个小要点

标签: java multithreading design-patterns


【解决方案1】:

您需要您的线程知道他们正在执行什么任务,以及他们正在为什么用户工作。但是,您需要有限数量的线程。

我认为在架构上,最好的方法是启动有限数量的线程,让它们能够处理来自任意用户的任务,但不允许多个线程同时为同一个用户工作。

为此,请保留三组用户对象,一组用于所有未完成任务的用户,一组用于分配了线程的用户,一组用于未分配线程的用户.将所有三个 Set 放在一个线程安全的用户跟踪对象中。您还需要从用户到任务的映射,或者如果您需要按照排队顺序完成任务,从用户到任务队列。

当您对任务进行排队时,在用户跟踪对象上进行同步,然后检查未完成任务的用户集。如果相关用户不存在,则创建它并将其放入任务未完成的用户集中,以及没有关联线程的用户集中。然后将任务放在从用户到任务的线程安全 Map 中。最后,在用户跟踪对象上退出同步。进行这种同步的最简单方法是将此处理放在用户跟踪对象中的同步方法中。

每个线程都分配给一个用户,该用户可能为空。线程通过在用户跟踪对象上同步来开始其循环,然后如果有可用的任务则获取任务。

为了获得一个任务,线程首先检查它是否已经分配给一个非空用户。如果是,它会检查地图以查找该用户的任务。如果它找到一个,线程从地图中删除该任务以进行服务。如果它没有找到该用户的任务,则将用户从任务不完整的用户集中删除,并从分配线程的用户集中删除,然后将分配给它的用户设置为 null。

如果线程被分配给一个空用户,它会检查没有分配线程的用户集。如果找到一个,它将自己分配给该用户,并将该用户从没有分配线程的用户集中移动到有分配线程的用户集中。然后该线程检查 Map 中与该用户关联的任务 - 保证有一个 - 并将其删除以进行服务。

在获得任务后,但在服务它之前,线程退出在用户跟踪对象上同步的代码块。同样,在获取任务的过程中,最好在用户跟踪对象中使用同步方法。退出同步块后,线程完成任务。如果线程最终没有获得任务,因为除了已经分配了线程的用户之外没有其他可用的任务,线程可以在唤醒并重新检查之前休眠一段时间,但这应该在同步块之外。

您可能可以找出自己使用的特定类。您可以通过让线程退出而不是休眠,然后根据需要重新启动它们来变得更复杂,但最好一开始就保持简单。

【讨论】:

    猜你喜欢
    • 2010-11-09
    • 1970-01-01
    • 2013-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-30
    相关资源
    最近更新 更多