2016-09-01 28 views
1

我有一个Person,我试图填充。许多setter方法需要时间来填充,因为数据是从DB调用中提供的,可能需要一些时间(超过10秒)才能返回。并发问题的最佳方法

我正在寻找最佳方式来异步填充我的增变器,然后将我的Person返回给调用方法。

下面是一个例子:

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

+0

提供的答案是完美的,但你仍然可以看看RxJava(Observable) – Rishi

回答

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将这两种期货套入一个更大的期货可以让我们到那里。在两个内部期货都完成之前,未来本身并不完整。

最后,我们joinallOf未来,它在继续之前等待它完成。如果这些代码中的任何一个可能会抛出异常,那么join会自己抛出异常 - 虽然它将被封装在CompletionException中 - 所以如果您愿意,您可以添加try/catch。


不幸的是,Java的这个概念,Future首次尝试,是一种动力不足,乏善可陈类。他们用CompletableFuture得到了正确的结果,但Future偷走了理想的名字。

+0

这似乎正是我所期待的。明天我会给它一个旋风。谢谢! – Dan

+1

在投入生产之前,应该明确在同一个'dmvService'实例上同时调用'getTicketsById'和'getAccidentsById'是否是值,即实现是否线程安全以及是否有实际的好处;在同一'Person'实例上同时调用'setTickets'和'setAccidentRecord'也是如此。目前还不清楚'dmvService'查询或'Person'的设置是否是实际的瓶颈。不幸的是,数据库驱动程序通常通过序列化操作来实现线程安全,这降低了并发的有效性... – Holger

+0

当我尝试执行此操作时,我不断收到在另一个会话中管理'dmvService'的错误,并且当前没有会话可用 – Dan