0

Having read a lot of different things and not being totally familiar with the correct terms for some of these things, I am wondering what the correct way is for creating threads at time of tomcat startup that have a specific purpose. I am using a linux system.

I am not trying to create a thread from a servlet, and I have a good idea of why this is bad. When tomcat starts up, I want two different threads that have a distinct purpose to start. The first thread runs on a period, every 30 minutes, to audit back-end data. The second thread is responsible for sending emails. When a request runs a servlet where an email must be sent, instead of holding up the servlet waiting for the email to be sent, I want to send a request to this email thread and move on. So one runs periodically, and one runs on demand. I never need to increase the number of threads performing these tasks, I just need these two going, and for it to be going as long as the webapp is running, and if the webapp has to halt, I don't really care about graceful shutdown.

There are a few approaches I know that I could take:

  1. Create a process running outside of tomcat and define a way to communicate with that process from my servlet. I'd like to avoid this if possible, because I'd like for these two threads to first be directly associated with start up and shut down of the webapp, and for them to be able to access data in the ServletContext, and to not have to ser/des data across a communication channel.

  2. Spawn two threads in the init method of one of my servlets. This seems dirty and hackish, but it would definitely get the job done.

  3. Create a ServletContextListener that extends a ThreadPoolExecutor or other ExexutorService. This seems appealing and correct, and I suppose I could do a fixed thread pool of 2 threads because I don't need any more. But is this the recommended way to do what I am trying? I understand that an ExecutorService is really more meant for executing Runnables on the fly without having to lose the overhead of creating a thread. I don't know if that is totally right, but if it is, I would not be using an executor for its meant purpose.

Maybe there are more methods that I do not know about, or a correct way to implement one of the above.

Michael Plautz
  • 2,888
  • 4
  • 21
  • 34
  • 2
    First, **this has nothing to do with Tomcat**, please edit the question. You question is how do you start service threads in a _web application_. Second, your third approach is almost correct - but don't `extends`, this is certainly wrong. Also, consider two listeners as these seem to be separate concerns and grouping them together is also a hack. Make sure you understand and use a `ScheduledExecutorService` and make sure you shut down your executors correctly. – Boris the Spider Sep 29 '14 at 13:45
  • Sounds to me like what you really want is two [Singleton](http://stackoverflow.com/q/70689/823393)s. – OldCurmudgeon Sep 29 '14 at 14:08
  • Regarding this having nothing to do with tomcat, I mention tomcat specifically because I would try to do something like this in WebSphere with a `WorkManager`, and I would pass `Work` to it. I do not believe Tomcat by itself has this capability (though I think JBOSS might), so I specifically am interested in options for a lightweight servlet processor like Tomcat. – Michael Plautz Sep 29 '14 at 18:29

2 Answers2

1

Please refer to the following Q&A: tomcat 6 thread pool for asynchronous processing.

Also, instead of Executors.newFixedThreadPool you'll probably need Executors.newScheduledThreadPool to create instance of ScheduledExecutorService which is capable of executing repeating tasks.

Hope this helps...

Community
  • 1
  • 1
Yuriy Nakonechnyy
  • 3,584
  • 4
  • 27
  • 41
  • Does it make sense to use both `Executors.newFixedThreadPool` for a single on-demand thread and `Executors.newScheduledThreadPool` for my periodic task? Would it make more sense to just choose one, for example, the `fixedThreadPool` for both threads and just adapt my periodic task to that? (As in use a `Thread.sleep(30 minutes)` to ensure periodicity?) – Michael Plautz Sep 29 '14 at 17:49
  • 1
    @MichaelPlautz Don't use the same pool for both tasks as the two tasks are completely unrelated (from the way your have described them). And **never** use `Thread.sleep` - if you are considering using it then you are doing something very wrong. – Boris the Spider Sep 30 '14 at 07:42
  • @MichaelPlautz I totally agree with `Boris the Spider` - **never** use **Thread.sleep** or similar methods because it's **low-level way** of working with multi-threading in Java and should be used **only** if one needs very specific multi-threading logic which can't be achieved using **ExecutorService** and/or **ScheduledExecutorService**, which are considered as **high-level** (and thus **less bug-prone**) way of working with multi-threading in Java. – Yuriy Nakonechnyy Sep 30 '14 at 08:58
  • @MichaelPlautz concerning which **ExecutorServices** to use: I suggest you to have **one instance** of **ScheduledExecutorService** created by calling `ScheduledExecutorService service = newScheduledThreadPool(numberOfThreadsInPool);`. Now, you'll obviously need at least 2 threads in pool for your 2 periodic tasks + some threads for other (non-periodic) asynchronous tasks which may occur during webapp lifetime. **Threads are not that expensive in Java**, so having 10 threads in pool will not significantly affect memory/performance and yet should suffice for the basic needs. Hope this helps... – Yuriy Nakonechnyy Sep 30 '14 at 09:09
1

i will not go on implementing the Thread pool itself, but on your question:

Correct way to create task threads in tomcat at startup

as others said, your third approach is almost correct BUT this depends on your Service Structure.

i'll give you an example and then explain it:

public class YourServletContextListener implements ServletContextListener{     
    @Override
    public void contextDestroyed(ServletContextEvent sce) {

    }         
    @Override
    public void contextInitialized(ServletContextEvent sce) {

    }
}

From the Docs:

contextInitialized:

All ServletContextListeners are notified of context initialization before any filter or servlet in the web application is initialized.

if i understand your approach correctly, then i would ask you: how would you like to start a service or send any request to a servlet that is still not been initialized?

this would work, if Services you would like to start do not communicate/need any servlet or Filter or any Data from the web App directly. later, after startup the container, they can sure communicate with each other.

as i said before, which way is the best to use depends on the Service Structure/Logic.

One other method may be using a filter:

void init(FilterConfig filterConfig) throws ServletException

Called by the web container to indicate to a filter that it is being placed into service. The servlet container calls the init method exactly once after instantiating the filter.

void destroy()

Called by the web container to indicate to a filter that it is being taken out of service. This method is only called once all threads within the filter's doFilter method have exited or after a timeout period has passed. After the web container calls this method, it will not call the doFilter method again on this instance of the filter.

This method gives the filter an opportunity to clean up any resources that are being held (for example, memory, file handles, threads) and make sure that any persistent state is synchronized with the filter's current state in memory.

but a filter is not designed for such approachs!

Use a Filter if you want to intercept on HTTP requests maching a specific URL pattern because you want to check/modify the HTTP request/response. Use a ServletContextListener if you want to intercept on webapp's startup and/or shutdown.

Rami.Q
  • 2,406
  • 2
  • 17
  • 29