2009-09-10 10 views
5

MODIFICA: Ora sono sicuro che il problema è correlato al ciclo while (true) che contiene tutti gli altri comandi come ho commentato e l'applicazione distribuisce senza l'eccezione allegata. Io non sono sicuro di quanto sia importante, ma il mio ServletContextListener applicazione si presenta così:Come creare un thread che viene eseguito sempre durante l'esecuzione dell'applicazione

public class BidPushService implements ServletContextListener{

public void contextInitialized(ServletContextEvent sce) { 
//Some init code not relevant, omitted for clarity 
     BidPushThread t= new BidPushThread(); 
     t.setServletContext(sce.getServletContext()); 
     t.run(); 
} 

Così ora il thread viene eseguito quando l'applicazione viene distribuita, ma perché il ciclo è commentato while non ha alcun significato reale .

Ho bisogno di avere un thread in esecuzione in background quando la mia applicazione carica e costantemente (senza un timeout) controlla una certa coda per gli oggetti. Ovviamente, una volta che ci sono degli oggetti, "si prende cura di loro" e poi continua a controllare la coda.

Attualmente sto implementando l'interfaccia ServletContextListener e mi chiamano al caricamento dell'applicazione. In esso, eseguo alcune operazioni di manutenzione e avvio una discussione ereditata da java.lang.Thread.

Qui è dove inizia il mio problema (o almeno così penso). Nel mio metodo run(), ho un

while (true) { 
    //some code which doesn't put the thread to sleep ever 
} 

Quando cerco di distribuire la mia applicazione al server ottengo un java.util.concurrent.TimeOutException. Cosa sto sbagliando?

Non è possibile avere una discussione che è sempre in esecuzione? Quando l'app viene rimossa, quella discussione viene interrotta dall'evento corrispondente nel mio ServletContextListener.

Ho davvero bisogno di qualcosa che continui a controllare la coda senza indugio.

Grazie mille per qualsiasi aiuto!

Edit: Questa è la traccia dello stack

GlassFish: deploy is failing= 
    java.util.concurrent.TimeoutException 
    at java.util.concurrent.FutureTask$Sync.innerGet(Unknown Source) 
    at java.util.concurrent.FutureTask.get(Unknown Source) 
    at com.sun.enterprise.jst.server.sunappsrv.SunAppServerBehaviour.publishDeployedDirectory(SunAppServerBehaviour.java:710) 
    at com.sun.enterprise.jst.server.sunappsrv.SunAppServerBehaviour.publishModuleForGlassFishV3(SunAppServerBehaviour.java:569) 
    at com.sun.enterprise.jst.server.sunappsrv.SunAppServerBehaviour.publishModule(SunAppServerBehaviour.java:266) 
    at org.eclipse.wst.server.core.model.ServerBehaviourDelegate.publishModule(ServerBehaviourDelegate.java:948) 
    at org.eclipse.wst.server.core.model.ServerBehaviourDelegate.publishModules(ServerBehaviourDelegate.java:1038) 
    at org.eclipse.wst.server.core.model.ServerBehaviourDelegate.publish(ServerBehaviourDelegate.java:872) 
    at org.eclipse.wst.server.core.model.ServerBehaviourDelegate.publish(ServerBehaviourDelegate.java:708) 
    at org.eclipse.wst.server.core.internal.Server.publishImpl(Server.java:2690) 
    at org.eclipse.wst.server.core.internal.Server$PublishJob.run(Server.java:272) 
    at org.eclipse.core.internal.jobs.Worker.run(Worker.java:55) 

My Code:

public class BidPushThread extends Thread { 
    private ServletContext sc=null; 
    @Override 
    public void run() { 
     if (sc!=null){ 
      final Map<String, List<AsyncContext>> aucWatchers = (Map<String, List<AsyncContext>>) sc.getAttribute("aucWatchers"); 
      BlockingQueue<Bid> aucBids = (BlockingQueue<Bid>) sc.getAttribute("aucBids"); 

       Executor bidExecutor = Executors.newCachedThreadPool(); 
       final Executor watcherExecutor = Executors.newCachedThreadPool(); 
       while(true) 
       { 
       try // There are unpublished new bid events. 
       { 
        final Bid bid = aucBids.take(); 
        bidExecutor.execute(new Runnable(){ 
         public void run() { 
          List<AsyncContext> watchers = aucWatchers.get(bid.getAuctionId()); 
          for(final AsyncContext aCtx : watchers) 
          { 
          watcherExecutor.execute(new Runnable(){ 
           public void run() { 
            // publish a new bid event to a watcher 
            try { 
            aCtx.getResponse().getWriter().print("A new bid on the item was placed. The current price "+bid.getBid()+" , next bid price is "+(bid.getBid()+1)); 
           } catch (IOException e) { 
            // TODO Auto-generated catch block 
            e.printStackTrace(); 
           } 
           }; 
          }); 
          }       
         } 
        }); 
       } catch(InterruptedException e){} 
       } 

     } 
    } 
    public void setServletContext(ServletContext sc){ 
     this.sc=sc; 
    } 
} 

Ci scusiamo per la confusione di formattazione, ma per la vita del mio "codice di rientro da 4 spazi" semplicemente non funziona per me Modifica: leggi "BlockingQueue" e implementalo, ma sto ancora ricevendo la stessa identica eccezione e traccia dello stack. cambiato il codice di cui sopra in modo da riflettere l'uso di 'BlockingQueue'

+0

Avrete bisogno di darci la traccia dello stack dell'eccezione – skaffman

+0

Si prega di mostrare il codice. Esistono pochissime classi nell'API Java che generano l'eccezione che si sta ricevendo e il loro utilizzo non corrisponde alla descrizione fornita. – SingleShot

+0

Dovresti sicuramente usare una coda di blocco. Il JavaDocs per http://java.sun.com/javase/6/docs/api/java/util/concurrent/BlockingQueue.html ha un codice di esempio. –

risposta

3

Il codice non avvia un nuovo thread, esegue il ciclo nello stesso thread ed è per questo che si verifica un errore di timeout quando distribuito.

Per avviare una discussione è necessario chiamare il metodo di avvio, non il metodo di esecuzione.

public void contextInitialized(ServletContextEvent sce) { 
//Some init code not relevant, omitted for clarity 
    BidPushThread t= new BidPushThread(); 
    t.setServletContext(sce.getServletContext()); 
    t.start();// run(); 
} 
+0

Wow, hai assolutamente ragione! L'ho modificato per iniziare in precedenza con il passaggio al thread Daemon "solo perché" come si dice e ha iniziato a funzionare e non mi rendevo conto che era dovuto a quello. (Ora ho provato e questo è quello che mi ha fermato). Grazie mille. – Ittai

+0

Ho fatto lo stesso errore :-( – Serxipc

+0

Ha! Ben individuato, solo il tipo di cosa che potrebbero mettere in quegli stupidi test di Java: avere uno snippet che chiama Thread.run() invece di Thread.start() e chiedi "Cosa c'è di sbagliato in questo codice?" –

0

Date un'occhiata a java.langThread.setDaemon() metodo, può è quello che ti serve

3

Questa sarebbe una pessima idea. Provocherebbe un carico della CPU del 100% senza una buona ragione.

La soluzione corretta è probabilmente quella di bloccare il thread quando la coda è vuota. Questo è banalmente implementato con un BlockingQueue.

+0

e qual è il tempo di risposta per questo? Voglio dire che questo non è implementato con sleep() ma il 'BlockingQueue' stesso risveglia il thread se capisco correttamente, quindi è immediato? – Ittai

+0

Il tempo di risposta sarebbe dominato dall'utilità di pianificazione dei thread del sistema operativo. Il thread in attesa è bloccato a livello di sistema operativo. Quando la coda si riempie, viene segnalato il sistema operativo. A quel punto il thread è cambiato dall'attesa al runnable, e se una CPU/core è disponibile in quel momento il thread è probabilmente eseguito immediatamente. Perché è stato in attesa, probabilmente otterrà anche un aumento di priorità. – MSalters

+0

Su un sistema Windows, il tempo di attesa da un blocco può arrivare a 10 millisecondi, in un sistema unix molto meno. –

5

setDaemon

SINTESI:

  • Marks questa discussione sia come thread demone o un thread utente.La Java Virtual Machine termina quando i thread solo in esecuzione sono tutti daemon thread.
  • Questo metodo deve essere chiamato prima dell'avvio del thread.
  • Questo metodo chiama innanzitutto il metodo checkAccess di questo thread
    senza argomenti. Ciò potrebbe causare lanciando un SecurityException (nel thread corrente
    ).

Threads

SOMMARIO: In molti casi, ciò che realmente vogliamo è creare thread in background che fanno semplici, task periodici in un'applicazione . Il metodo setDaemon() può essere utilizzato per contrassegnare una discussione come thread daemon da eliminare e scartata quando non rimangono altri thread di applicazione . Di norma, , l'interprete Java continua a eseguire fino al completamento di tutti i thread. Ma quando i thread daemon sono gli unici thread ancora in vita, l'interprete uscirà.

+0

Mi dispiace di non poter accettare due risposte, ma in realtà entrambi voi e MSalters avevano ragione, avevo bisogno di correggere entrambi gli errori in modo che il problema potesse essere risolto. Ti ho comunque dato uno, grazie per lo sforzo. – Ittai

1
Can't I have a thread which is always running? When the app is removed, 
that thread is stopped by the corresponding event in my ServletContextListener. 

"Quel filo è ferma"? Come? Non esiste una condizione di terminazione nel tuo ciclo while (vero) {...}. Come lo fermi? Stai usando il metodo Thread.stop()? Non è sicuro ed è stato ritirato in Java 1.1

Se si utilizza setDaemon (true), il thread rimarrà attivo dopo aver arrestato l'app Web utilizzando gli strumenti di gestione del server delle app. Quindi, se riavvii l'app Web, otterrai un altro thread. Anche se si tenta di annullare la distribuzione dell'app Web, il thread rimarrà in esecuzione e impedirà che l'intera app Web venga raccolta dai dati inutili. Quindi ridistribuire la prossima versione ti darà una copia aggiuntiva di tutto ciò che è in memoria.

Se si fornisce una condizione di uscita per il loop (ad esempio InterruptedException o un volatile "stopNow" booleano), è possibile evitare questo problema.

Problemi correlati