2013-04-03 6 views

risposta

3

Leggi su ScheduledExecutorService esso deve essere iniziata da un ServletContextListener

public class MyContext implements ServletContextListener 
{ 
    private ScheduledExecutorService sched; 

    @Override 
    public void contextInitialized(ServletContextEvent event) 
    { 
     sched = Executors.newSingleThreadScheduledExecutor(); 
     sched.scheduleAtFixedRate(new MyTask(), 0, 10, TimeUnit.MINUTES); 
    } 

    @Override 
    public void contextDestroyed(ServletContextEvent event) 
    { 
     sched.shutdownNow(); 
    } 
} 

Inoltre, si potrebbe provare a utilizzare il Java Timer da un ServletContextListener ma non è raccomandato in un container Java EE dal momento che toglie il controllo del Infilare le risorse dal contenitore. (la prima opzione con ScheduledExecutorService è la strada da percorrere).

Timer timer = new Timer("MyTimer"); 
MyTask t = new MyTask(); 

//Second Parameter is the specified the Starting Time for your timer in 
//MilliSeconds or Date 

//Third Parameter is the specified the Period between consecutive 
//calling for the method. 

timer.schedule(t, 0, 1000*60*10); 

E MyTask che implementa TimerTask è una classe che implementa l'interfaccia Runnable quindi bisogna ignorare il metodo run con il tuo codice:

class MyTask extends TimerTask 
{ 
    public void run() 
    { 
    // your code here 
    } 
} 
+0

Ok, ho capito. Ma da dove devo chiamare questo metodo. Devo avviarlo non appena la mia applicazione è attiva –

+2

[Non usare mai 'Timer' in Java EE] (http://stackoverflow.com/questions/9173132/stop-scheduled-timer-when-shutdown-tomcat/9186070#9186070). – BalusC

+0

Grazie a @BalusC ho menzionato esplicitamente che nella mia risposta. – user1697575

10

Come sei su Tomcat, che è solo un barebone servletcontainer, non è possibile utilizzare EJB @Schedule per questo, che è raccomandato dalla specifica Java EE. La soluzione migliore è quindi il ScheduledExecutorService dal pacchetto java.util.concurrent di Java 1.5. È possibile attivare questo con l'aiuto di un ServletContextListener come segue:

@WebListener 
public class BackgroundJobManager implements ServletContextListener { 

    private ScheduledExecutorService scheduler; 

    @Override 
    public void contextInitialized(ServletContextEvent event) { 
     scheduler = Executors.newSingleThreadScheduledExecutor(); 
     scheduler.scheduleAtFixedRate(new SomeTask(), 0, 10, TimeUnit.MINUTES); 
    } 

    @Override 
    public void contextDestroyed(ServletContextEvent event) { 
     scheduler.shutdownNow(); 
    } 

} 

dove lo sguardo SomeTask classe come questa:

public class SomeTask implements Runnable { 

    @Override 
    public void run() { 
     // Do your job here. 
    } 

} 

Se stavi in ​​realtà utilizzando un vero e proprio contenitore Java EE con il supporto EJB e tutti su em (come Glassfish, JBoss AS, TomEE, ecc.), quindi è possibile utilizzare un EJB @Singleton con un metodo @Schedule. In questo modo il contenitore si preoccuperà di raggruppare e distruggere i thread. Tutto ciò che serve è allora la seguente EJB:

@Singleton 
public class SomeTask { 

    @Schedule(hour="*", minute="*/10", second="0", persistent=false) 
    public void run() { 
     // Do your job here. 
    } 

} 

Si noti che in questo modo è possibile continuare a utilizzare in modo trasparente contenitore gestito transazioni solito modo (@PersistenceContext e così via), che non è possibile con ScheduledExecutorService — Avresti per ottenere manualmente il gestore di entità e avviare manualmente/commit/terminare la transazione, ma per impostazione predefinita non si dispone già di un'altra opzione su un servlet contenitore barebone come Tomcat.

Si noti che non si dovrebbe mai usare un Timer in un'applicazione Web Java EE apparentemente "a vita" in esecuzione. Ha i seguenti problemi principali che lo rende inadatto per l'uso in Java EE (citato da Java Concurrency in Practice):

  • Timer è sensibile ai cambiamenti del clock di sistema, ScheduledExecutorService non è.
  • Timer ha solo un thread di esecuzione, quindi un'attività a esecuzione prolungata può ritardare altre attività. ScheduledExecutorService può essere configurato con qualsiasi numero di thread.
  • Qualsiasi eccezione di runtime generata in un TimerTask uccide quello thread, rendendo così Timer morto, vale a dire che le attività pianificate non verranno più eseguite (finché non si riavvia il server). ScheduledThreadExecutor non solo rileva le eccezioni di runtime, ma ti consente di gestirle se lo desideri. L'attività che ha generato un'eccezione verrà annullata, ma altre attività continueranno a essere eseguite.
+0

Ottima risposta, grazie @BalusC. Una domanda però: come modificherei lo scheduler se avessi bisogno di cambiare l'intervallo tra le chiamate? ad es. Ho un po 'di frequenza' che può essere impostata dall'utente in webgui che rappresenta il tempo tra le esecuzioni in secondi. – Gewure