首页 > 解决方案 > Spring异步线程睡眠

问题描述

我有这段代码:

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这些步骤可能会发生:

  1. 主线程进入方法
  2. 线程池中的一个线程查询数据
  3. 主线程等待或剩余资源来做“其他”事情
  4. 如果线程池线程完成,我可以使用结果

我是否真的从这种情况中受益,因为我必须在每种情况下等待结果(调用服务方法异步同步)?
使用它是一种好习惯Thread.sleep()吗?

我可以从这个例子中想象的唯一好处是主线程是空闲的(未阻塞)用于其他计算(可能处理其他 Web 请求),而线程池线程执行耗时的过程?

标签: javaspringspring-bootasynchronous

解决方案


我是否真的从这种情况中受益,因为我必须在每种情况下等待结果(调用服务方法异步同步)?

不。您创建的内容本质上仍然是一个阻塞调用,但是您使它比简单的阻塞调用复杂得多:

ApplicationUser user = applicationUserService.findIncludePrivilegesById(id);

它还使用 2 个线程而不是 1 个线程,但您仍然只做一件事情。第二个线程正在执行伪忙等待,基本上只是询问另一个线程“我们到了吗?” 每 100 毫秒。

如果您的主线程还有实际工作要做sleep()(例如对不同的服务器执行第二次慢速调用),那么上面的代码将有一些优点。但即便如此,它也可能使代码混乱,因为它在特殊情况下执行手动多线程。一个小的重新设计可能是一个更好的选择。

使用 Thread.sleep() 是一种好习惯吗?

Thread.sleep()没有。除非你想暂停一个线程(这通常是非常不必要的),否则几乎没有理由调用。如果你正在考虑使用Thread.sleep(),你应该重新考虑你在做什么。

最后,你正在做的半忙等待

while (!user.isDone()) {
    Thread.sleep(100);
}

可以用 just 替换user.get(),这将阻塞(即睡眠)直到另一个线程完成。这将更有效(和同步)。因此,您不会从当前代码中获得任何优势。

如果您只是担心通话时间很长,并且您想将这段时间用于某些事情,请不要担心。该线程将处于等待状态,并且将有其他线程要运行。如果您遇到的情况是因为所有线程都在该调用上被阻塞而实际上资源不足,那么也许是时候看看为什么执行该调用需要这么长时间了?

现在有一些方法可以执行非阻塞调用以实际获得您正在考虑的一些好处,但这些方法需要驱动程序的支持,并且需要一种不同的编程方式,而无需求助于线程池或Futures.


推荐阅读