Контейнер Jboss Java EE и ExecutorService
У меня есть автономное приложение java, которое использовало ExecutorService для обработки нескольких заданий параллельно
ExecutorService es = Executors.newFixedThreadPool(10);
Теперь я хочу повторно использовать одно и то же решение в EJB bean, но я не уверен, как правильно инициализировать ThreadPool, так как я обычно оставляю контейнер Java EE для управления всеми ресурсами потока. Могу ли я использовать один и тот же код или есть альтернативный правильный способ получить пул управляемых потоков Jboss?
Ответы
Ответ 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.