What is recommended way for spawning threads from a servlet in Tomcat What is recommended way for spawning threads from a servlet in Tomcat multithreading multithreading

What is recommended way for spawning threads from a servlet in Tomcat


In a barebones servletcontainer like Tomcat or Jetty, your safest bet is using an applicaton wide thread pool with a max amount of threads, so that the tasks will be queued whenever necessary. The ExecutorService is very helpful in this.

Upon application startup or servlet initialization use the Executors class to create one:

executor = Executors.newFixedThreadPool(10); // Max 10 threads.

Then during servlet's service (you could ignore the result for the case that you aren't interested, or store it in the session for later access):

Future<ReturnType> result = executor.submit(new YourTask(yourData));

Where YourTask must implement Runnable or Callable and can look something like this, whereby yourData is just your data, e.g. populated with request parameter values (just keep in mind that you should absolutely not pass Servlet API artifacts such as HttpServletRequest or HttpServletResponse along!):

public class YourTask implements Runnable {    private YourData yourData;    public YourTask(YourData yourData) {        this.yourData = yourData;    }    @Override    public void run() {        // Do your task here based on your data.    }}

Finally, during application's shutdown or servlet's destroy you need to explicitly shutdown it, else the threads may run forever and prevent the server from properly shutting down.

executor.shutdownNow(); // Returns list of undone tasks, for the case that.

In case you're actually using a normal JEE server such as WildFly, Payara, TomEE, etc, where EJB is normally available, then you can simply put @Asynchronous annotation on an EJB method which you invoke from the servlet. You can optionally let it return a Future<T> with AsyncResult<T> as concrete value.

@Asynchronouspublic Future<ReturnType> submit() {    // ... Do your job here.    return new AsyncResult<ReturnType>(result);}

see also:


You could maybe use a CommonJ WorkManager (JSR 237) implementation like Foo-CommonJ:

CommonJ − JSR 237 Timer & WorkManager

Foo-CommonJ is a JSR 237 Timer and WorkManager implementation. It is designed to be used in containers that do not come with their own implementation – mainly plain servlet containers like Tomcat. It can also be used in fully blown Java EE applications servers that do not have a WorkManager API or have a non-standard API like JBoss.

Why using WorkManagers?

The common use case is that a Servlet or JSP needs to aggregate data from multiple sources and display them in one page. Doing your own threading a managed environement like a J2EE container is inappropriate and should never be done in application level code. In this case the WorkManager API can be used to retrieve the data in parallel.

Install/Deploy CommonJ

The deployment of JNDI resources vendor dependant. This implementation comes with a Factory class that implements the javax.naming.spi.ObjectFactory interface with makes it easily deployable in the most popular containers. It is also available as a JBoss service. more...

Update: Just to clarify, here is what the Concurrency Utilities for Java EE Preview (looks like this is the successor of JSR-236 & JSR-237) writes about unmanaged threads:

2.1 Container-Managed vs. Unmanaged Threads

Java EE application servers require resource management in order to centralize administration and protect application components from consuming unneeded resources. This can be achieved through the pooling of resources and managing a resource’s lifecycle. Using Java SE concurrency utilities such as the java.util.concurrency API, java.lang.Thread and java.util.Timer in a server application component such as a servlet or EJB are problematic since the container and server have no knowledge of these resources.

By extending the java.util.concurrent API, application servers and Java EE containers can become aware of the resources that are used and provide the proper execution context for the asynchronous operations to run with.

This is largely achieved by providing managed versions of the predominant java.util.concurrent.ExecutorService interfaces.

So nothing new IMO, the "old" problem is the same, unmanaged thread are still unmanaged threads:

  • They are unknown to the application server and do not have access to Java EE contextual information.
  • They can use resources on the back of the application server, and without any administration ability to control their number and resource usage, this can affect the application server's ability to recover resources from failure or to shutdown gracefully.

References


Spring supports asynchronous task (in your case long running) through spring-scheduling. Instead of using Java threads direct I suggest to use it with Quartz.

Recourses: