2016-01-13 68 views
5

我有兩個任務需要執行,分別是task1task2,它們是相同業務流程的一部分。當task1完成時,我必須對最終用戶做出響應,因此它的響應時間必須最小化。使用EJB的正確方法異步方法

我目前的做法是執行task1,只要task1完成,就異步調用task2方法。 task2是複雜的,它的響應時間超出了我的控制範圍,因爲它具有一些外部依賴性。

@Stateless 
public class SessionBean1 { 

    @Inject 
    SessionBean2 sessionBean2; 

    public void doTask1(){ 
     // task one stuff 
     sessionBean2.doTask2(); 
    } 

} 



@Stateless 
public class SessionBean2 { 

    @Asynchronous 
    public void doTask2(){ 
     // do task2 stuff 
    } 

} 

在websphere 8.0(所使用的EJB容器)中,同步方法和異步方法由不同的線程池運行。

我的初步假設是,即使task2表現不佳,task1也沒有影響,但可悲的是,事實並非如此。

如果task2執行得不好,異步線程池中的所有線程都將被佔用。這將導致task1等待異步線程空閒,因此task1會產生影響。

在websphrere服務器日誌的消息: The request buffer for thread pool WorkManager.WebSphere_EJB_Container_AsynchMethods_Internal_WorkManager has reached its capacity

我的問題是,這將是實現我想要在這裏實現有道。

+0

如果您使用的是Java EE 7,您可以使用@AccessTimeout(value = xx)批註,但我認爲Websphere是Java EE 6? – rjdkolb

+0

@mattfreake:如鏈接[image](http://2.1m.yt/itzn6So。jpg),異步方法請求的數量是有限的,並且取決於異步線程的數量。我可以增加線程的數量,但即使task2表現不佳,我的task1仍然需要等待。此外,線程的數量不受硬件配置的限制。 – ares

+1

使用@rjdkolb建議的JMS隊列的想法是一個更好的主意,如果調整線程池的大小是有問題的。 –

回答

2

另一種方法是增加「工作請求隊列管理控制檯中「EJB異步方法調用設置」的大小。這是一個隊列,在實際的線程池本身之前,所以這可能會給你多一點時間。

理想情況下,這應該與上面提到的超時結合使用。

+0

這似乎是一個不錯的選擇。默認情況下,它由運行時間處理,並取決於分配的線程數量,但我無法弄清楚有多少。請問websphrere管理控制檯的最後一行'運行時當前使用20中較大的值和最大線程數的值是否有意義? – ares

+0

看着你的圖像,我認爲它是「15或20中較大的一個」,因此在你的情況下它應該是20.你可以保持最大的線程池大小,並且將你的隊列增加到更大。我希望*隊列應該有一個很小的內存/處理器佔用空間,所以它可以存儲你對task2的等待請求,同時讓現有的請求完成並保持在你的硬件限制之內。但是如果任務2可以無限期地完成,那麼我認爲超時將是一條路 –

2

我認爲@AccessTimeout是你在找什麼。我看到一個示例here 這將限制.doTask2()可以運行的時間並避免您的問題。

@Stateless 
public class SessionBean1 { 

    @Inject 
    SessionBean2 sessionBean2; 

    public void doTask1(){ 
     // task one stuff 
     sessionBean2.doTask2(); 
    } 

} 

SessionBean2

@Stateless 
public class SessionBean2 { 
    @AccessTimeout(60000)//default timeunit is TimeUnit.MILLISECONDS 
    @Asynchronous 
    public void doTask2(){ 
     // do task2 stuff 
    } 

} 

作爲替代:

爲了限制時的異步過程可能需要,使用handle.get(XX,TimeUnit.xx );方法。您還需要返回Future,而不是僅僅使其失效。

我希望這適合您的使用情況下,您將需要調用。獲得

@Stateless 
public class SessionBean1 { 

    @Inject 
    SessionBean2 sessionBean2; 

    public void doTask1(){ 
     // task one stuff 
     Future<Void> handle = sessionBean2.doTask2(); 
     // do other stuff 
     handle.get(10, TimeUnit.SECONDS);//If you want to block later 

    } 

} 

SessionBean2

@Stateless 
public class SessionBean2 { 

    @Asynchronous 
    public Future<Void> doTask2(){ 
     // do task2 stuff 
     new AsyncResult<Void>(Void); 
    } 

} 
+0

我將在添加@AccessTimeout之後加載測試並讓您知道結果。但是在通話實際超時的情況下,我的task2將不會被調用。 – ares

+1

如果您希望它是異步的並且始終運行,請將消息放入JMS隊列 – rjdkolb

+0

...或使用可能更易於使用的EJB定時器。 –