Подтвердить что ты не робот

Контейнер Jboss Java EE и ExecutorService

У меня есть автономное приложение java, которое использовало ExecutorService для обработки нескольких заданий параллельно

 ExecutorService es = Executors.newFixedThreadPool(10);

Теперь я хочу повторно использовать одно и то же решение в EJB bean, но я не уверен, как правильно инициализировать ThreadPool, так как я обычно оставляю контейнер Java EE для управления всеми ресурсами потока. Могу ли я использовать один и тот же код или есть альтернативный правильный способ получить пул управляемых потоков Jboss?

4b9b3361

Ответ 1

Обязательное предупреждение. Создание собственных потоков на сервере приложений Java EE (даже Tomcat) не рекомендуется, так как это может быть огромная проблема с производительностью, и в большинстве случаев предотвратит работу контейнеров, таких как 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();
    }
}

Затем вы можете ссылаться на этот 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");

Ответ 2

Правильный способ сделать это в EJB - использовать ManagedExecutorService, который является частью API Concurrency Utils (Java EE7). Вы не должны использовать какой-либо ExecutorService, который является частью java.util.concurrent в вашем корпоративном коде.

Используя 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();
    }
}

Затем нам нужно вызвать задачу, передав ее, хотя и для метода submit() ManagedExecutorService.

@Stateless
public class ReportBean {

    @Resource
    private ManagedExecutorService executorService;

    public void runReports() {
        ReportTask reportTask = new ReportTask();
        Future<Report> future = executorService.submit(reportTask);
    }
}

Ответ 3

Ну... Решение David для меня не срабатывало по следующим причинам:

Вот что я сделал:
Моя установка:
- 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) и возитесь со значениями там Узнайте, как он себя ведет. Когда я использую потоки с аркиллианскими тестами, я получаю потоки, которые убиты, хотя мое время keepalive очень велико. Я думаю, что это связано с тем, как arquillian microdeploys. Когда arquillian заканчивает, все незавершенные нити убиты которые выполнялись во время выполнения тестов... по крайней мере, это то, что, я думаю, я наблюдаю. С другой стороны, все готовые потоки на самом деле вели себя хорошо в этом смысле, что они выполнили свои задачи/операции.

Надеюсь, что этот пост поможет!

Ответ 4

До EE7 вы можете использовать WorkManager из JSR 237

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

Эта спецификация в настоящее время снята, но некоторые серверы приложений ее реализуют. Я использую реализацию ibm в WebSphere 8.5 - IBM WorkManager. Это полностью управляемый ресурс, доступный в консоли администрирования. Обратите внимание, что он не совместим с интерфейсом 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.

Ответ 5

Если вы используете JBoss, вы можете использовать org.jboss.seam.async.ThreadPoolDispatcher.

ThreadPoolDispatcher полностью управляется.

Для других полезных управляемых классов см. пакет: org.jboss.seam.async.