OK. I'm going to do this in the abstract, since, while it's not that much to code, it's more than I can code correctly in a hurry.
First, you need to understand that HTTP is a request/response protocol, not a continuous-session (client/server) operation. So when you code a servlet,
JSP, or whatever, you're obligated to take the request, process it, and return the response as fast as possible. This is the main reason why the normal request handlers are forbidden to spawn threads. If you return the response, but you've spawned a
thread, it's tied to its parent and that can muck up the internal resource management of the server's request dispatcher.
So any threading you do has to be done somewhere safe. I used to to this with vendor-specific code, but it's more portable when you do it using regular webapp resources. A safe place to to this is in a servlet's init() method. Unlike the doGet/doPut and related routines, init() is invoked only once - when the servlet is constructed, and it's running under the same thread that controls the servlet as a whole, so no problem. Or at least none I know of!
You want to spawn an "engine" thread here, because the servlet won't be placed into service until init() returns. An engine is just a process that takes work in and does something, then returns to idle until the next
unit of work comes in. Unlike HTTP, however, where the handlers react to external requests, the engine obtains requests on its own.
The link between the HTTP and the engine is a Queue, most commonly a FIFO. There are a number of Java collection classes that can be used for this purpose. Vector is good, since it's thread-safe. The more general collection classes normally aren't, but they can be told to be thread-safe.
Thread-safe is important, since the HTTP and engine threads are 2 different threads and therefore a non-thread-safe structure can become corrupter if they both attempt to modify it at the same time.
There's one other item you need - a semaphore. This is a mechanism that causes a process to wait until there's data in the work queue. Otherwise, you'd sit and spin, polling and wasting CPU time. Or you could run a timer and poll periodically, which is more polite, but not as responsive as when you get a wake-up call as soon as something's posted to the work queue.
There are also some Java classes that provide both queue and semaphore as one - which is known as blocking. So if you haven't studied up on Java collections, this is a good excuse to learn them!
Here's an example, in brief:
Define a work queue. Let's say it's an array of Strings, each one being the name of a directory to delete. At init time, you start the engine thread. The engine goes to pull work from the queue, but there is no work, so the engine goes to sleep.
Now an HTTP request comes in. The request handler adds an entry to the engine's work queue and returns a "Work has been scheduled" message to the user.The queue manager wakes up the engine and it pulls the request off the queue and executes it.When the request finished, the engine attempts to pull another request and repeat the process. If other requests have come in, the dequeuing operation will return immediately with the next request
string. If the queue is empty, the engine goes back to sleep until more work arrives.
In REALLY busy environments, the engine might not do the work directly. Instead it might construct multiple sub-threads and pass each request to a sub-thread. Usually you set an upper limit on the number of sub-threads, and you might even pool them. You can get very elaborate if you need to.