Jboss Java EE容器和ExecutorService

我有一个独立的Java应用程序,它使用ExecutorService并行处理大量作业

ExecutorService es = Executors.newFixedThreadPool(10); 

我现在想在EJB bean中重用相同的解决方案但不确定如何正确初始化ThreadPool,因为我通常会让Java EE容器控制所有线程资源。 我可以使用相同的代码,还是有另一种正确的方法来获取Jboss托管线程池?

在EJB中执行此操作的正确方法是使用ManagedExecutorService,它是Concurrency Utils API(Java EE7)的一部分。 您不应该使用属于企业代码中java.util.concurrent的任何ExecutorService。

通过使用ManagedExecutorService,您的新线程将由容器创建和管理。

以下示例来自我的网站。

要使用ManagedExecutorService创建新线程,首先要创建一个实现Callable的任务对象。 在call()方法中,我们将定义我们想要在单独的线程中执行的工作。

 public class ReportTask implements Callable { Logger logger = Logger.getLogger(getClass().getSimpleName()); public Report call() { try { Thread.sleep(3000); catch (InterruptedException e) { logger.log(Level.SEVERE, "Thread interrupted", e); } return new Report(); } } 

然后我们需要通过将任务传递给ManagedExecutorService的submit()方法来调用该任务。

 @Stateless public class ReportBean { @Resource private ManagedExecutorService executorService; public void runReports() { ReportTask reportTask = new ReportTask(); Future future = executorService.submit(reportTask); } } 

强制警告:不鼓励在Java EE应用服务器(甚至Tomcat)中创建自己的线程,因为它可能是一个巨大的性能问题,并且在大多数情况下会阻止容器function(如JNDI)工作。 新线程将不知道它们属于哪个应用程序,将不会设置Thread上下文类加载器以及许多其他隐藏的问题。

幸运的是,有一种方法可以让Java EE服务器通过Java EE 6 @Asynchronous和这种聪明的设计模式来管理线程池。 可移植到任何Java EE 6认证的服务器。

在您的应用程序中创建此EJB。

 package org.superbiz; import javax.ejb.Asynchronous; import javax.ejb.EJB; import javax.ejb.Stateless; import java.util.concurrent.Callable; import java.util.concurrent.Executor; @Stateless(name="Executor") public class ExecutorBean implements Executor { @Asynchronous @Override public void execute(Runnable command) { command.run(); } } 

然后,您可以通过普通dependency injection在您的应用程序的其他位置引用此bean(如果引用组件是Servlet,Listener,Filter,其他EJB,JSF Managed bean)。

 @EJB private Executor executor; 

然后像往常一样使用Executor

如果组件不是另一个Java EE组件,则可以通过以下方式查找bean:

 InitialContext initialContext = new InitialContext(); Executor executor = (Executor) initialContext.lookup("java:module/Executor"); 

嗯…… David的解决方案对我不起作用,原因如下:

  1. 编译器喋喋不休地说java.util.concurrent是不允许的……在JBOSS范围内哪种有意义。
  2. 另外:公共STATIC课……? 阅读本文: 为什么你不能在Java中将类声明为静态?

这是我做的:
我的安装:
– JBOSS AS 7.1.1
– Java 1.6
– RHEL
– 使用Gradle和Arquillian运行示例:

 @Stateless public class ExecutorBean { @Asynchronous public void execute(Runnable command) { command.run(); } } 

然后你的客户端看起来像这样:

 @EJB ExecutorBean eb; @Test public void testExecutorBean() { eb.execute(new YourCustomizedRunnableWhichDoesALotOfUsefulStuff()); assertFalse(!true); } 

但请注意:在我的standalone.xml中(或者一般来说,我的JBOSS配置文件我有一个’线程池’部分。看看它(如果你碰巧使用JBOSSAS)并修改那里的值。找出来它是如何表现的。当我使用带有arquillian测试的线程时,我得到的线程虽然我的保持时间非常高但已被杀死。我认为这与arquillian microdeploys有关。当arquillian完成所有未完成的线程被杀死时正在运行测试正在进行中……至少这是我认为我观察到的。另一方面,所有完成的线程在这个意义上表现得很好,他们完成了任务/操作。

希望这篇文章有帮助!

在EE7之前,您可能希望使用JSR 237中的WorkManager

http://docs.oracle.com/javaee/1.4/api/javax/resource/spi/work/WorkManager.html

此规范目前已撤销,仍有一些应用服务器实现它。 我在WebSphere 8.5中使用ibm实现 – IBM WorkManager 。 它是完全托管的资源,可在管理控制台中使用。 请注意,它与Oracle不兼容。

以下是IBM版本的示例:

 @Resource(lookup = "wm/default") WorkManager workManager; public void process() { try { ArrayList workItems = new ArrayList(); for (int i = 0; i < 100; i++) { // submit 100 jobs workItems.add(workManager.startWork(new Work() { @Override public void run() { try { System.out.println(Thread.currentThread().getName() + " Running"); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } @Override public void release() { System.out.println(Thread.currentThread().getName() + " Released"); } })); } // wait for all jobs to be done. workManager.join(workItems, WorkManager.JOIN_AND, 100000); } catch (WorkException e) { e.printStackTrace(); } } 

我也知道Commonj Workmanager 。

如果您使用的是JBoss,则可以使用org.jboss.seam.async.ThreadPoolDispatcher。

ThreadPoolDispatcher是完全托管的。

对于其他有用的托管类,请参阅包:org.jboss.seam.async。