并发问题的最佳方法

时间:2016-09-01 01:01:20

标签: java multithreading concurrency

我想要填充Person。许多setter方法需要一些时间来填充,因为数据是从DB调用提供的,可能需要一些时间(超过10秒)才能返回。

我正在寻找在将Person返回给调用方法之前异步填充mutators的最佳方法。

以下是一个例子:

Person p = service.getPersonById(id);
// populate from DMV DB
p.setTickets(dmvService.getTicketsById(id));  // takes 15 seconds to return data
p.setAccidentRecord(dmvService.getAccidentsById(id));  // takes 10 seconds.
...
...

return p;

我希望能够异步运行我的方法(setTicketssetAccidentRecord等),以将我的加载时间从25秒减少到15秒左右。

1 个答案:

答案 0 :(得分:2)

在Java 8中引入的

CompletableFuture 就是故障单。它是一个monadic,可链接的类,可以轻松管理线程外计算。

未来代表将在未来某个时间完成并产生结果的计算。它可能已经完成,或者在某些后台线程中可能需要一段时间。 CompletableFuture建立在这个核心概念的基础上,允许您将各种其他转换和处理程序附加到现有的未来。

Person p = service.getPersonById(id);

CompletableFuture.allOf(
    CompletableFuture.supplyAsync(() -> dmvService.getTicketsById(id))
                     .thenAccept(p::setTickets),

    CompletableFuture.supplyAsync(() -> dmvService.getAccidentsById(id))
                     .thenAccept(p::setAccidentRecord)
).join();

return p;

在您的情况下,您可以使用supplyAsync在后台主题中运行getTicketsByIdgetAccidentsById。由于您希望在这些方法返回时调用相应的setter,您可以使用thenAccept来表示,"当该方法返回时,将值提供给此setter"。

您有两个背景计算,并且您不想在两个完成之前返回。用allOf将这两个期货包装成一个更大的期货让我们在那里。 allOf未来本身并未完成,直到两个内部期货都完成为止。

最后,我们join allOf未来,在继续之前等待它完成。如果这些代码中的任何一个可能抛出异常,那么join将自己抛出该异常 - 尽管它将被包装在CompletionException中 - 因此如果您愿意,可以在其周围添加try / catch

不幸的是,Java首次尝试这个概念Future,是一个动力不足,乏善可陈的阶级。他们用CompletableFuture做对了,但是Future偷走了理想的名字。