29

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

 ExecutorService es = Executors.newFixedThreadPool(10);

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

4

5 回答 5

34

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

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

以下示例取自我的网站

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

public class ReportTask implements Callable<Report> {

    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<Report> future = executorService.submit(reportTask);
    }
}
于 2013-10-16T13:20:30.390 回答
27

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

幸运的是,有一种方法可以让 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();
    }
}

然后,您可以通过简单的依赖注入在应用程序的其他地方引用此 bean(如果引用组件是 Servlet、Listener、Filter、其他 EJB、JSF 托管 bean)。

@EJB
private Executor executor;

然后Executor正常使用。

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

InitialContext initialContext = new InitialContext();
Executor executor = (Executor) initialContext.lookup("java:module/Executor");
于 2012-12-19T04:33:10.653 回答
5

嗯......大卫的解决方案对我不起作用,原因如下:

  1. 编译器一直在抱怨 java.util.concurrent 是不允许的……这在 JBOSS 范围内是有道理的。
  2. 另外:公共静态类...?阅读本文:为什么不能在 Java 中将类声明为静态?

这是我所做的:
我的安装:
- JBOSS AS 7.1.1
- Java 1.6
- RHEL - 使用GradleArquillian
运行示例:

@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 测试的线程时,尽管我的 keepalive-time 非常高,但我得到的线程被杀死了。我认为这与 arquillian 微部署的方式有关。当 arquillian 完成时,所有正在运行的未完成线程都被杀死在运行测试时……至少我认为我观察到了这一点。另一方面,所有已完成的线程实际上都表现良好,因为它们完成了任务/操作。

希望这篇文章有帮助!

于 2013-05-03T13:24:29.797 回答
3

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

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

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

以下是 IBM 版本的示例:

@Resource(lookup = "wm/default")
WorkManager workManager;

public void process() {
    try {
        ArrayList<WorkItem> workItems = new ArrayList<WorkItem>();
        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

于 2013-11-28T09:18:20.973 回答
0

如果你使用 JBoss,你可以使用 org.jboss.seam.async.ThreadPoolDispatcher。

ThreadPoolDispatcher 是完全托管的。

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

于 2017-04-27T15:45:49.757 回答