Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Running a background Java program in Tomcat [duplicate]

Can anyone advise here? I have a situation where users will submit data mining requests interactively via a Java JSP and servlet to an application of mine which will dynamically work out association rules on data and more.

As such a job may take a while, I'm thinking of some sort of process on the server to run such a request in the background so it dosen't 'lock' the session and possibly use massive amounts of server memory to the detriment of the system.

As the system is made up of a series of Java JSPs and servlets running in a Tomcat container over a MySQL database, can anyone advise a way forward?

Thanks

Mr Morgan

like image 952
mr morgan Avatar asked Feb 05 '11 14:02

mr morgan


People also ask

How does Tomcat run Java code?

To run java program automatically on tomcat startup, need to use Servlet and this Servlet initialized on tomcat startup automatically. To execute a program, you have to use Servlet and Servlet should define in deployment descriptor web. xml file under WEB-INF folder. web.

Is Tomcat dependency on Java?

The Maven pom. xml contains dependencies for the embedded Tomcat server and the assembler plugin, which builds the application. Dependencies for JSP container are not included in this application, since we only have a servlet. The EmbeddedTomcatEx is a Java console application, which includes an embedded Tomcat server.


2 Answers

Use an ExecutorService.

There's a few things you should do though, mark the thread as a daemon thread so it atleast won't tie up tomcat in error scenarios, and you should stop the executor when your servlet context is destroyed (e.g. when you redeploy or stop your application. To do this, use a ServletContextListener:

public class ExecutorContextListener implements ServletContextListener {     private  ExecutorService executor;      public void contextInitialized(ServletContextEvent arg0) {         ServletContext context = arg0.getServletContext();         int nr_executors = 1;         ThreadFactory daemonFactory = new DaemonThreadFactory();         try {             nr_executors = Integer.parseInt(context.getInitParameter("nr-executors"));         } catch (NumberFormatException ignore ) {}          if(nr_executors <= 1) {         executor = Executors.newSingleThreadExecutor(daemonFactory);         } else {         executor = Executors.newFixedThreadPool(nr_executors,daemonFactory);        }           context.setAttribute("MY_EXECUTOR", executor);       }      public void contextDestroyed(ServletContextEvent arg0) {         ServletContext context = arg0.getServletContext();         executor.shutdownNow(); // or process/wait until all pending jobs are done     }  } import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory;  /**  * Hands out threads from the wrapped threadfactory with setDeamon(true), so the  * threads won't keep the JVM alive when it should otherwise exit.  */ public class DaemonThreadFactory implements ThreadFactory {      private final ThreadFactory factory;      /**      * Construct a ThreadFactory with setDeamon(true) using      * Executors.defaultThreadFactory()      */     public DaemonThreadFactory() {         this(Executors.defaultThreadFactory());     }      /**      * Construct a ThreadFactory with setDeamon(true) wrapping the given factory      *       * @param thread      *            factory to wrap      */     public DaemonThreadFactory(ThreadFactory factory) {         if (factory == null)             throw new NullPointerException("factory cannot be null");         this.factory = factory;     }      public Thread newThread(Runnable r) {         final Thread t = factory.newThread(r);         t.setDaemon(true);         return t;     } } 

You'll have to add the context listener to your web.xml, where you also can specify the number of threads you'll want to run the background jobs:

  <listener>     <listener-class>com.example.ExecutorContextListener</listener-class>   </listener> 

You can access the executor from your servlet and submit jobs to it:

ExecutorService executor = (ExecutorService )getServletContext().getAttribute("MY_EXECUTOR"); ... executor.submit(myJob); 

If you're using Spring, all this can probably be made even simpler

like image 113
nos Avatar answered Sep 24 '22 13:09

nos


I think Quartz scheduler should be able to accomplish what you want to do here. Here are some of the examples from Quartz. Using this, you can start a cron that rapidly polls to process the incoming request(s). I actually did that for one of my projects.

like image 42
limc Avatar answered Sep 22 '22 13:09

limc