Spring异步线程睡眠

4

I have this piece of code:

final Future<ApplicationUser> user = applicationUserService.findIncludePrivilegesById(id);
    while (!user.isDone()) {
        Thread.sleep(100);
    }
    if (user.get() == null) throw new Exception(this.getMessageSource().getMessage("label.error.findError",
            null, locale));
    model.addAttribute("user", new ApplicationUserDto(user.get()));

    model.addAttribute("roles", Role.valuesMinusApi());
    model.addAttribute("groups", completeAuthorityList);
    model.addAttribute("message", this.getMessageSource().getMessage("label.dialog.userEdit", new Object[]{user.get().getLogin()}, locale));
    model.addAttribute("applicationUserStates", ApplicationUserState.values());
    return "administration/edit";
applicationUserService.findIncludePrivilegesById(id) 方法会去远程数据库服务器查询数据。
我在设计这段代码时的想法是通过使用 async 让这个耗时的数据库通信处理一个自由线程池中的线程。

就我所理解的整个 async 过程,可能会出现以下步骤:

  1. 主线程进入方法
  2. 线程池中的一个线程查询数据
  3. 主线程等待或拥有剩余资源来做“其他”事情
  4. 如果线程池线程完成了任务,我可以使用它的结果
在所有情况下(异步调用服务方法还是同步调用),我都必须等待结果,那我真的从这个场景中获益了吗?
使用 Thread.sleep() 是好的实践吗?
我唯一能想象到的好处是,当线程池线程执行耗时操作时,主线程是自由的(未被阻塞),可以处理其他计算(也许是处理其他Web请求)。
1个回答

6
我真的从这种情况中获益吗?因为我必须在每种情况下等待结果(异步或同步调用服务方法)。 不。你所创建的本质上仍然是一个阻塞调用,但是你把它变得比简单的阻塞调用要复杂得多。
ApplicationUser user = applicationUserService.findIncludePrivilegesById(id);

它还使用了2个线程而不是1个,但你仍然只做了一个事情。第二个线程执行伪busy-waiting,每100ms基本上只询问另一个线程“到了吗?”。
如果主线程除了sleep()(例如对另一个服务器执行第二次慢调用)之外有实际工作要做,则上述代码可能会有一些优点。但即使有这种情况,它也可能会使代码变得混乱,因为它在特定情况下进行手动多线程处理,重新设计可能是更好的选择。
引用:

使用Thread.sleep()好吗?

不好。除非您想暂停线程(这通常非常不必要),否则几乎没有理由调用Thread.sleep()。如果您正在考虑使用Thread.sleep(),则应重新考虑您正在做什么。
最后,你所做的半忙等待
while (!user.isDone()) {
    Thread.sleep(100);
}

可以使用 user.get() 替换整个代码段,这样会阻塞 (即休眠) 直到另一个线程完成。这样会更加高效 (同步)。因此,当前的代码并没有任何优势。

如果你只是担心有一次长时间的调用,而你希望利用这段时间做其他事情, 那么不用担心。那个线程将处于等待状态,还有其他线程可以运行。如果你的情况是所有线程都被阻塞在该调用上导致资源耗尽,那么可能需要看看为什么执行该调用需要这么长时间?

现在有一些方法可以进行非阻塞调用来获得您所考虑的一些好处,但这些方法需要从 驱动程序 得到支持,并需要采用不同的编程方式,而不是使用线程池或Futures


你建议同步进行这个耗时的计算吗?还是在此期间(即在while循环中)做“其他”事情,直到耗时操作完成? - Thomas Lang
1
@ThomasLang 我建议做最简单的事情,即执行常规的阻塞/同步调用。 虽然从理论上讲,您可以同时执行“其他”操作,但在实践中,效果并不那么好。请查看我的编辑,特别是底部的内容,这些是您可能正在考虑的事情。 - Kayaman
非常感谢您详细的解释。顺便问一下,您认为像这样的CompletableFuture怎么样:https://spring.io/guides/gs/async-method/ - Thomas Lang
@ThomasLang 与普通的 Future 相比,CF 更可取,并且 Spring 可以在 某些情况下 自动利用它。该指南展示了一种更清晰的编写代码的方式,类似于您所拥有的实际并行工作(您没有)。难点在于知道何时使用异步方法。该指南具有我描述的相同的合成示例:多个缓慢的调用。除非您正在处理遗留代码,否则您需要修复为什么这些调用需要如此长时间。因此,请阅读该指南以获取技术细节,而不是设计或使用指南。 - Kayaman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接