2011-03-09 86 views
1

我完全不熟悉jsr166y庫,並且使用forkjoin庫編寫了一個例程,該庫分割了一個查詢並且同時運行它與數據庫副本。我在下面放了一個片段。 SelectTask擴展了RecursiveTask。Java ForkJoin Future似乎過早完成

ForkJoinExecutor fjPool; 
    Future queryResultsFut = null; 
     for (int i = 1; i <= lastBatchNum; i++) { 

...

SelectTask selectMatchesRecursiveTask = new SelectMatchesTask(loadBalancer.getDao(), thisRuleBatch, queryResults); 
    queryResultsFut = fjPool.submit(selectMatchesRecursiveTask); 
} 

queryResultsFut.get(); 

的get方法的調用是爲了阻止父線程,直到所有查詢結果返回,這樣處理可以在彙總結果開始。

在CI環境中運行一段時間後,我發現現在並不總是這樣。當數據庫較慢時,即使任務仍在運行,線程也會繼續。這在我看來與我閱讀的文檔相矛盾。

也許我這樣做是錯誤的方式?我應該擴展ForkJoinTask而不是RecursiveTask嗎?

回答

3

你可能不應該使用ForkJoin。 FJ框架是專門爲CPU密集型的非阻塞任務並行性設計的,但您專門用它來阻塞任務(外部數據庫查詢)。我建議你使用正常的執行者框架來執行你正在做的事情。

與您的問題相匹配的FJ的唯一方面是任務分解。儘管如此,通過簡單的n路分割或更復雜的遞歸策略,手動操作不會太困難。

+0

感謝您的啓發。您是否會知道執行程序框架是否包含將視爲「假設所有已完成」方面的內容,這些方面我都假設爲fork連接的設計目的? – barrymac 2011-03-10 11:38:03

+0

其實它看起來像我應該使用Phaser來實現帶有ForkJoinPool的CyclicBarrier:http://gee.cs.oswego.edu/dl/jsr166/dist/jsr166ydocs/jsr166y/Phaser.html – barrymac 2011-03-10 11:50:08

+0

不知道爲什麼你想要等待它們全部完成,但是'ExecutorService.invokeAll(Collection >)'返回'List >'的結果。當你遍歷它並獲得每個將來阻塞的結果,直到未來完成爲止,因此,在完成所有工作之前,不要完成迭代。如果你想以完成順序得到結果,你可以使用'CompletionService'。 – 2011-03-10 23:00:43

1

RecursiveTask繼承它從ForkJoinTask獲得的功能,所以擴展ForkJoinTask不會有不同的效果。請記住,每次提交時都會得到不同的ForkJoinTask返回。你調用fjPool.submit多少次?如果你正在做的更多,那麼一旦你將得到你提交的最後一項任務,並且queryResultsFut將在最後一項任務完成時完成(即從get中返回)。

由於您現在正在處理ForkJoin池,您應該在提交後返回ForkJoinTask而不是Future。 JF框架的主要目的是分治和處理。當你能夠將問題分解成更小的類似問題時,它們是非常有用的,並行執行它們然後結合結果並返回。

+0

感謝在清除了。我曾假設該框架通過未來分享未來實例並使用它來等待所有分叉任務完成。 – barrymac 2011-03-10 11:15:58

+1

由於您正在使用RecursiveTask,因此我們的想法是遞歸提交到fork連接池。當你到達遞歸集合的末尾時,你會得到結果並將它與相同級別的相應分叉連接起來。您返回該結果並重復 – 2011-03-10 14:18:45

+2

但是,至少您要查找的內容考慮一個ExecutorCompletionService http://download.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/ExecutorCompletionService.html – 2011-03-10 14:19:32