A former colleague of mine and me worked to figure out why our Web Service Application was slowing down and always leaves lots of run-away processes. Here are some of the findings we had implemented to keep our application rolling! The sample codes below reflects a reporting process where requests to generate a report is made and how the threads handle the status of each requests.
Use Java Concurrency API
There are only three classes that I've used to implement a MultiThreaded WS Application.
Runnable, ScheduledExecutorService, and ConcurrentLinkedQueue.
The ScheduledExecutorService implements ExecutorService and is of type Executor. Executor is responsible for abstracting the gory details of implementing threads into simpler methods. And it works all the time.
ScheduledExecutorService allows you to provide what the initial time is to run the thread associated with it, at what frequency, the thread to run and the unit of time. Was very easy to use and you can configure the thread pool size as well. The application I wrote had 5 threads running concurrently and it never had any problems at all. They all shared the ConcurrentLinkedQueue object resource and I didn't use the synchronized keyword to make this object thread safe since by default it already is.
Using the Runnable interface is better than just extending the Thread class. It promotes less coupling. Here's a sample of how this thread is plugged-in to the ScheduledExecutorService.
Implement the ServiceLifeCycle
Implementing ServiceLifeCycle will allow you to put shutdown hooks and implement its destroy() method where you can manipulate how the spawned threads are to be shutdown/killed. The init(Object context) method must also be implemented.
The shutDownMonitor() method is called and the ExecutorService's awaitTermination() method is invoked which basically gracefully shuts down the spawned thread in the WS Container according to the specified time (might be in seconds, minutes, hours). You can also force to shutdown all threads by calling the method shutdownNow() if it takes longer than the specified time.
Use "application" Scoping
When you use "request" scope as configured in your wsdd file, you are creating one instane of the service per request. If several requests were triggered, your application is also spawning threads per request. The previous request that was processed left a trail of run-away processes. If the scope was "application" it will create only one instance of the service that will serve multiple requests. Hence, when the application runs it does not create run away processes since we already have a shutdown hook to kill all of the spawned threads before the application completely shutdown.
I think it all depends on what an application is trying to achieve, it might have more complex business process than this sample code we have and it requires more classes to use from the concurrent api. But in a multithreaded web service application, you definitely want to use the application scope and implement a shutdown hook.