2011-02-05 24 views
39

Qualcuno può consigliare qui? Ho una situazione in cui gli utenti invieranno richieste di data mining interattivamente tramite un JSP Java e servlet a una mia applicazione che elaborerà dinamicamente le regole di associazione sui dati e altro ancora.Esecuzione di un programma Java in background in Tomcat

Dato che un tale lavoro potrebbe richiedere un po 'di tempo, sto pensando ad una sorta di processo sul server per eseguire tale richiesta in background in modo da non bloccare la sessione e possibilmente utilizzare enormi quantità di server memoria a discapito del sistema.

Poiché il sistema è costituito da una serie di JSP e servlet Java in esecuzione in un contenitore Tomcat su un database MySQL, qualcuno può consigliare una soluzione?

Grazie

MORGAN

+0

Ti aspetti di dare una risposta indietro? Inoltre, Tomcat utilizza threadpool che possono espandersi quando necessario per soddisfare più richieste simultanee. –

+0

È necessario visualizzare i risultati delle "richieste di data mining" agli utenti (o almeno notificarli dei lavori completati)? E come hai bisogno di farlo? –

+0

Stavo pensando che quando un lavoro è finito, l'utente può essere inviato via email per dire che i risultati sono disponibili. –

risposta

5

penso quarzo pianificatore dovrebbe essere in grado di realizzare ciò che si vuole fare qui. Ecco alcuni degli examples from Quartz. Usando questo, è possibile avviare un cron che esegue rapidamente il polling per elaborare le richieste in entrata. L'ho fatto per uno dei miei progetti.

+0

Uso Quartz altrove nel sistema per i lavori programmati ogni ora, ma è una possibilità. –

+3

Il quarzo è una buona chiamata. Farà "Esegui il lavoro una volta, ora" abbastanza bene.L'altro vantaggio è che ti darà la possibilità di riavviare. Quando avvii il lavoro, il quarzo può "salvare" la richiesta e ricominciare il lavoro in caso di arresto del sistema. Ottieni tutto ciò "gratuitamente", e dal momento che lo hai già, sai già come usarlo. Perché aggiungere un nuovo kit allo stack se non è necessario? –

+0

@Will: +1 ... ben detto. :) – limc

0

Forse JMS è quello che realmente cercando però richiede uno sforzo in più da usare che su Tomcat, perché è solo Servlet Container. Si può eigher interruttore per reale AppServer come Glassfish o JBoss o aggiungere funzionalità JMS per Tomcat da soli (il collegamento sotto)

http://blogs.captechconsulting.com/blog/jairo-vazquez/tomcat-and-jms

48

Utilizzare un ExecutorService.

Ci sono alcune cose che dovresti fare, contrassegnare il thread come un daemon thread in modo che almeno non leghi tomcat in scenari di errore, e dovresti interrompere l'executor quando il contesto del servlet è distrutto (ad esempio quando ridistribuisci o interrompere l'applicazione per fare questo, utilizzare un 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; 
    } 
} 

dovrete aggiungere il listener contesto al vostro web.xml, in cui è anche possibile specificare il numero di thread si desidera eseguire i lavori in background:

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

È possibile accedere l'esecutore dal servlet e inviare i lavori ad esso:

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

Se stai usando primavera, tutto questo può probabilmente essere reso ancora simpler

+0

In che modo un thread non demone legherà tomcat in uno scenario di errore? –

+0

Stavo percorrendo questa strada, ma sono preoccupato di poter arrestare il mio ExecutorService in modo affidabile e sicuro quando Tomcat si sta spegnendo. Non posso perdere ciò che sta eseguendo. Apparentemente non puoi dipendere da ServletContextListener. Vedi http://stackoverflow.com/questions/1549924/shutdown-hook-for-java-web-application e http://stackoverflow.com/questions/11443133/shutdown-hook-in-tomcat-necessable-not-running –

+0

@nos, quindi myJob Runnable dovrebbe avere un metodo run come 'while (true) {Thread.sleep (1000); // fare qualcosa di più ..} '. non è vero?] –

Problemi correlati