I have a standalone java app which used the ExecutorService to process a number of jobs in parallel
ExecutorService es = Executors.newFixedThreadPool(10);
I now want to re-use the same solution within an EJB bean but am unsure how to correctly initialize the ThreadPool, since I'd normally leave the Java EE container to control all thread resources. Can I just use the same code or is there an alternative correct way to get a Jboss managed thread pool?
The Java ExecutorService is a construct that allows you to pass a task to be executed by a thread asynchronously. The executor service creates and maintains a reusable pool of threads for executing submitted tasks.
The ExecutorService helps in maintaining a pool of threads and assigns them tasks. It also provides the facility to queue up tasks until there is a free thread available if the number of tasks is more than the threads available.
ExecutorService is a JDK API that simplifies running tasks in asynchronous mode. Generally speaking, ExecutorService automatically provides a pool of threads and an API for assigning tasks to it.
Here is an example of executing a Runnable with an ExecutorService : ExecutorService executorService = Executors. newSingleThreadExecutor(); executorService. execute(new Runnable() { public void run() { System.
The correct way to do this in your EJB is to use the ManagedExecutorService, which is part of the Concurrency Utils API (Java EE7). You shouldn't be using any ExecutorService that is part of the java.util.concurrent in your enterprise code.
By using the ManagedExecutorService your new thread will be created and managed by the container.
The following example is taken from my site here.
To create a new thread using a ManagedExecutorService, first create a task object that implements Callable. Within the call() method we will define the work that we want carried out in a separate thread.
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(); } }
Then we need to invoke the task by passing it though to the submit() method of the ManagedExecutorService.
@Stateless public class ReportBean { @Resource private ManagedExecutorService executorService; public void runReports() { ReportTask reportTask = new ReportTask(); Future<Report> future = executorService.submit(reportTask); } }
Obligatory warning: Creating your own threads in a Java EE app server (even Tomcat) is discouraged as it can be a huge performance issue and in most cases will prevent container functionality, such as JNDI, from working. The new threads won't know which application they belong to, the Thread context classloader will not be set and many other hidden issues.
Fortunately there is a way to get the Java EE server to manage the thread pool via the Java EE 6 @Asynchronous
and this clever design pattern. Portable to any Java EE 6 certified server.
Create this EJB in your application.
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(); } }
Then you can refer to this bean elsewhere in your application via plain dependency injection (if the referring component is a Servlet, Listener, Filter, other EJB, JSF Managed bean).
@EJB private Executor executor;
Then use the Executor
as normal.
If the component is not another Java EE component, you can lookup the bean via:
InitialContext initialContext = new InitialContext(); Executor executor = (Executor) initialContext.lookup("java:module/Executor");
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With