views:

205

answers:

4

Probably a repeat! I am using Tomcat as my server and want to know what is best way to spawn threads in the servlet with deterministic outcomes. I am running some long running updates from a servlet action and would like for the request to complete and the updates to happen in the background. Instead of adding a messaging middleware like RabbitMQ, I thought I could spawn a thread that could run in the background and finish in its own time. I read in other SO threads that the server terminates threads spawned by the server in order for it to manage resources well.

Is there a recommended way of spawning threads, background jobs when using Tomcat. I also use Spring MVC for the application.

+2  A: 

Strictly speaking, you're not allowed to spawn threads according to the JEE spec. I would also consider the possibility of a denial of service attack (deliberate or otherwise) if multiple requests come in at once.

A middleware solution would definitely be more robust and standards-compliant.

dty
The thing with the JEE spec is that in JEE5 you can't use asynchronous calls since @Asynchronous was only added in JEE6. I agree most of the time it's a bad idea to use threads, but sometimes you have to.
Colin Hebert
@Colin Java EE 5 has JMS or the WorkManager API, @Asynchronous is definitely not a panacea for all kind of background jobs.
Pascal Thivent
The middleware solution is what I thought of first, problem is that its a lot of re-architecting and generally very time consuming. And the number of such operations aren't too many either.
Ritesh M Nayak
+8  A: 

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.

Do during application startup or servlet initialization:

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):

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

Finally, during application's shutdown or servlet's destroy:

executor.shutdownNow(); // Returns list of undone tasks, for the case that.
BalusC
I'd consider it good practice to mark those executor threads as daemon threads, otherwise you'll prevent tomcat to shut down if one of your tasks have gone wild. You can do that by passing in a ThreadFactory to one of the Executors.newXXX methods. Having a ServletContextListener to shut down the executor you created is a must too.
nos
@nos: good point wrt daemon threads. But sometimes you'd like to have them to finish their task to avoid broken results (they might be writing to a file or DB, etc). Depends all on functional requirement which is yet unclear in the original question. Also, if those are to be used by a single servlet, creating and shutting down them in servlet's `init()` and `destroy()` is sufficient. Else doing in a `ServletContextListener` is indeed better, you could then make it available to more servlets.
BalusC
I like this solution but wont I lose context of what the Job is for? I would want some logic built into the thread based on who spawns the thread and perform some operations on it. The Quartz solution looks really good as well.
Ritesh M Nayak
Then just pass that through as constructor argument of `CallableTask`.
BalusC
+3  A: 

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:

Jaydeep
+1 Spring + quartz is very easy to set up, and does a decent job for many situations.
bwawok
I found the quartz scheduler mechanism to be really good. I am using the TaskScheduler bean to do all of the background processing.
Ritesh M Nayak
+2  A: 

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 JEE 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

Pascal Thivent
Noted should be that this JSR is from 2003, far before `java.util.concurrent` in Java 1.5 was introduced which makes thread management much more robust.
BalusC
Pascal Thivent
Yes, the awareness of the container of those threads would overall have more benefits in the thread management. It's then controllable at container level instead of webapp level. Thanks for the update, interesting information.
BalusC
Pascal Thivent