如何处理需要合并以创建响应的多个客户端请求?

How do I handle multiple client requests which need to be combined to create a response?

我正在使用 JAX-RS 来处理客户端请求。场景是这样的:客户端被分成 5 个组。每个客户端需要向服务器提交一个数字,当属于同一组的所有 5 个客户端完成提交他们的数字时,服务器计算这些数字的总和 return是他们所有人的结果。

因为当客户提交一个数字时,他们必须等待其他人也这样做(如果他们不是最后一个)我正在使用异步响应 API 允许等待其他客户端而不会使服务器超载。假设没有超时限制。

我对 JAX-RS、会话和上下文的内部工作原理缺乏了解,这让我很难为此设计合适的解决方案。这是我的想法(在混合代码伪代码中):

public class SummationResource {

    @Inject
    SummationService service; // talks with the entity manager

             //group    client  number
    static Map<Long, Map<Long, Integer>> groupMap;

    @POST
    @Path("{clientId}")
    public void submit(int num,
                        @PathParam("clientId") long clientId,
                        @Suspended AsyncResponse response) {
        new Thread() {
            @Override
            public void run() {
                long groupId = service.getGroupOfClient(clientId);
                Map<Long, Integer> clients = groupMap.get(groupId);
                clients.put(clientId, num);
                if (clients.size() != 5)
                    // wait (see points below)
                else
                    // release all threads of this group
                int sum = HelperClass.sum(clients.values()); // should be executed only once
                response.resume(sum);
            }
        }.start();
    }
}

我想接触的点:

我正在寻找一种设计来解决上述请求和要点,类似于我在代码中所做的。

  1. groupMap 是静态的,因此只要应用程序存在,所有调用都将是同一个实例。但是还没有创建实例。 Java 提供同步集合,因此您无需费心同步对它的访问:

    static Map<Long, Map<Long, Integer>> groupMap = Collections.synchronizedMap( new HashMap<>());
    

并且您应该至少用您的客户填充一次(目前客户将为空)。

  1. 对于等待,我建议使用 CompletableFuture,它可以 return 自定义类型的结果,为您的每个 groupId 使用一个:

    Map<Long, CompletableFuture> futures = Collections.synchronizedMap( new HashMap<>());
    

每个必须等待的线程(clients.size() < 5)将自己的未来添加到此映射:

    CompletableFuture<Integer> future = new CompletableFuture<>();
    futures.put(clientId, future);
    int sum = future.get();

计算总和的第 5 个线程将完成所有这些未来,传递计算的总和。

    futures.values().forEach( i -> i.complete( sum));