Domanda

EDIT: Ora sono sicuro che il problema è legato al      while (true) contiene tutti gli altri comandi mentre l'ho commentato e l'applicazione viene distribuita senza l'eccezione allegata. Non sono sicuro di quanto sia importante, ma la mia implementazione ServletContextListener è simile a questa:

         la classe pubblica BidPushService implementa ServletContextListener {

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

Quindi ora il thread viene eseguito quando viene distribuita l'app, ma poiché il ciclo while è commentato, non ha alcun significato reale.

Devo eseguire un thread in background quando l'applicazione viene caricata e controllare costantemente (senza un timeout) una determinata coda per gli oggetti. Naturalmente, una volta che ci sono oggetti, "si prende cura di loro" e quindi continua a controllare la coda.

Attualmente sto implementando l'interfaccia ServletContextListener e mi viene chiamato quando l'app viene caricata. In esso, faccio alcune cose di manutenzione e inizio un thread che ho ereditato da java.lang.Thread .

Ecco 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 provo a distribuire la mia app sul server ricevo un java.util.concurrent.TimeOutException . Cosa sto sbagliando?

Non posso avere un thread sempre in esecuzione? Quando l'app viene rimossa, quel thread viene interrotto dall'evento corrispondente nel mio ServletContextListener .

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

Grazie mille per qualsiasi aiuto!

Modifica: 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)

Il mio codice:

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 il disordine di formattazione ma per la durata del mio codice "indent" di 4 spazi " semplicemente non funziona per me Modifica: leggi "BlockingQueue" e implementato, ma sto ancora ottenendo la stessa esatta eccezione e traccia dello stack. ha modificato il codice sopra riportato per riflettere l'uso di 'BlockingQueue'

È stato utile?

Soluzione

Il tuo codice non avvia un nuovo thread, esegue il loop nello stesso thread ed è per questo che stai ricevendo un errore di timeout quando distribuito.

Per avviare un thread devi chiamare il metodo start, non il metodo run.

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

Altri suggerimenti

setDaemon

  

SINTESI:

     
      
  • Contrassegna questo thread come thread daemon o thread utente. Il   Java Virtual Machine esce quando   solo i thread in esecuzione sono tutti daemon   filettature.
  •   
  • Questo metodo deve essere chiamato prima di avviare il thread.
  •   
  • Questo metodo prima chiama il metodo checkAccess di questo thread
      senza argomenti. Ciò può comportare   lanciare SecurityException (nella
      thread corrente).
  •   

Discussioni

  

SINTESI: in molti casi, ciò che realmente   voglio è creare thread in background   che svolgono compiti semplici e periodici in un   applicazione. Il metodo setDaemon ()   può essere usato per contrassegnare un thread come a   thread demone che dovrebbe essere ucciso   e scartato quando nessun altro   i thread dell'applicazione rimangono. Normalmente,   l'interprete Java continua a funzionare   fino al completamento di tutti i thread. Ma   quando i thread daemon sono gli unici   fili ancora vivi, l'interprete   uscirà.

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 .

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.

" Quella discussione è stata fermata " ;? Come? Non ci sono condizioni di terminazione nel tuo ciclo while (true) {...}. Come lo stai fermando? Stai usando il metodo Thread.stop ()? Non è sicuro ed è stato deprecato molto tempo fa 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 proprio 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 in modo inutile. Quindi la ridistribuzione della versione successiva ti darà una copia aggiuntiva di tutto ciò che è in memoria.

Se fornisci una condizione di uscita per il loop (ad es. InterruptedException o un valore booleano "stopNow" volatile), puoi evitare questo problema.

Dai un'occhiata al metodo java.langThread.setDaemon (), può essere quello che ti serve

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top