在 Java 中同步多个异步请求

Posted

技术标签:

【中文标题】在 Java 中同步多个异步请求【英文标题】:Syncing multiple asynchronous requests in Java 【发布时间】:2019-01-05 12:37:34 【问题描述】:

我正在使用 Java 中的官方 Telegram Api (TDLib) 来请求有关组的所有成员的信息。使用他们的 ID,我向服务器发送异步请求,并在 ResultHandler 中为每个请求接收 User 对象,如下所示:

private static ArrayList<TdApi.User> chatUsers= new ArrayList<>();

private static void addUsers()

    for (int i = 0; i < userIDs.length; i++)

        client.send(new TdApi.GetUser(userIDs[i]), new Client.ResultHandler() 

                        @Override
                        public void onResult(TdApi.Object object) 
                            TdApi.User user = (TdApi.User)object;
                            chatUsers.add(user);
                        
        );
    

由于我对 Java 中的任何同步请求都很陌生,我想知道以下几点:

    调用此方法并等待收到所有结果后再继续操作的合适方法是什么?

    通常,当连续调用多个请求并在继续下一个请求之前等待每个结果时,通常的方法是什么而不是将请求嵌套在彼此内部以在 Java 中同步它们?我想避免这样的事情:

    private static void getSupergroupId(int chatId)
    
    //first step
    client.send(new TdApi.GetChat(chatId), new Client.ResultHandler() 
                @Override
                public void onResult(TdApi.Object object) 
                    supergroupId = ((TdApi.ChatTypeSupergroup)((TdApi.Chat)object).type).supergroupId;
    
                    //second step when result received
                    client.send(new TdApi.GetSupergroupMembers(supergroupId, null, 0, 200), new Client.ResultHandler() 
                        @Override
                        public void onResult(TdApi.Object object) 
                            chatMembers = ((TdApi.ChatMembers)object).members;
    
                            //further steps which need to wait for the result of the step before
                        
                    );
                
    );
    
    

谢谢!

【问题讨论】:

Client.ResultHandler是接口吗? 是的。你可以在这里看到它:github.com/tdlib/td/blob/master/example/java/org/drinkless/… 【参考方案1】:

1 Java 同步器之一应该可以工作。我会从CountDownLatch 开始,因为它是最简单的。

  private static final ArrayList<TdApi.User> chatUsers = Collections.synchronizedList(new ArrayList<>());

  private static void addUsers() 
    final CountDownLatch latch = new CountDownLatch(userIDs.length);
    for (int i = 0; i < userIDs.length; i++) 
      client.send(new TdApi.GetUser(userIDs[i]), new Client.ResultHandler() 
        @Override
        public void onResult(TdApi.Object object) 
          TdApi.User user = (TdApi.User) object;
          chatUsers.add(user);
          latch.countDown();
        
      );
    
    // handle InterruptedException
    latch.await(10, TimeUnit.SECONDS);
  

请注意,chatUsers 是从不同的线程访问的,因此对它的访问应该由锁保护。为了简单起见,我在示例中使用了Collections.synchronizedList。但是,您应该使用更细粒度的方法。

2 看看Completablefuture,好像就是你要找的。​​p>

  private static void getSupergroupId(int chatId) 
    CompletableFuture.supplyAsync(() -> 
      AtomicReference<TdApi.ChatTypeSupergroup> atomicReference = new AtomicReference<>();
      CountDownLatch latch = new CountDownLatch(1);
      client.send(new TdApi.GetChat(chatId), new Client.ResultHandler() 
        @Override
        public void onResult(TdApi.Object object) 
          atomicReference.set(((TdApi.ChatTypeSupergroup) ((TdApi.Chat) object).type).supergroupId);
          latch.countDown();
        
      );
      // handle InterruptedException
      latch.await(10, TimeUnit.SECONDS);
      return atomicReference.get();
    ).thenApply(supergroupId -> 
      AtomicReference<TdApi.ChatMembers> atomicReference = new AtomicReference<>();
      CountDownLatch latch = new CountDownLatch(1);
      client.send(new TdApi.GetSupergroupMembers(supergroupId, null, 0, 200), new Client.ResultHandler() 
        @Override
        public void onResult(TdApi.Object object) 
          atomicReference.set((TdApi.ChatMembers) object).members;
          latch.countDown();
        
      );
      // handle InterruptedException
      latch.await(10, TimeUnit.SECONDS);
      return atomicReference.get();
    );
    //further steps which need to wait for the result of the step before)
  

请注意,与CountDownLatch 相同的技巧用于等待结果。同样,回调的结果应该由锁保护,因为它被不同的线程访问。为了 100% 清楚,它不是必需的,因为搭载 CountDownLatch 但是我建议无论如何都使用显式同步,例如 AtomicReference

【讨论】:

以上是关于在 Java 中同步多个异步请求的主要内容,如果未能解决你的问题,请参考以下文章

同步请求和异步请求区别

JavaScript实现多个异步请求有序且同步完成

Java 使用CountDownLatch实现网络同步请求,异步同时获取商品信息组装

Java 使用CountDownLatch实现网络同步请求,异步同时获取商品信息组装

JavaScript实现多个异步请求有序且同步完成

如何在 Objective-C 中管理、跟踪或同步多个服务器的异步请求?