2016-01-13 69 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定时器。 –