2016-09-01 27 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