2009-09-10 22 views
5

EDIT: Ahora estoy seguro de que el problema está relacionado con el while (true) lazo que sostiene todos los otros comandos como he comentado a cabo y los despliega aplicaciones sin la excepción adjunta. No estoy seguro de cuánto es importante pero mi ServletContextListener aplicación se ve así:Cómo crear un hilo que corre todo el tiempo que mi aplicación se está ejecutando

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(); 
} 

Así que ahora el hilo se ejecute cuando se despliega la aplicación, pero debido a que el bucle while se comenta que no tiene significado real .

Necesito tener una secuencia de ejecución en segundo plano cuando se carga mi aplicación y constantemente (sin tiempo de espera) verificar una cierta cola de objetos. Por supuesto, una vez que hay objetos, "los cuida" y luego continúa revisando la cola.

Actualmente, estoy implementando la interfaz ServletContextListener y me llaman cuando se carga la aplicación. En él, hago algunas cosas de mantenimiento y comienzo un hilo que heredé de java.lang.Thread.

Aquí es donde comienza mi problema (o eso creo). En mi método run(), tengo un

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

Cuando intento de desplegar mi aplicación al servidor consigo un java.util.concurrent.TimeOutException. ¿Qué estoy haciendo mal?

¿No puedo tener un hilo que esté siempre en ejecución? Cuando se elimina la aplicación, ese hilo es detenido por el evento correspondiente en mi ServletContextListener.

Realmente necesito algo que siga revisando la cola sin demora.

¡Muchas gracias por cualquier ayuda!

Editar: Este es el seguimiento de la pila

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) 

Mi Código:

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; 
    } 
} 

Lo siento por el desorden formato, pero para la vida de mi "código de guión por 4 espacios" simplemente no funciona para mí Editar: Lea sobre 'BlockingQueue' y lo implementé, pero todavía estoy obteniendo la misma excepción y el mismo stack stack. cambiado el código anterior para reflejar el uso de 'BlockingQueue'

+0

Necesitará darnos el rastro de la pila de la excepción – skaffman

+0

Por favor muestre su código. Hay muy pocas clases en la API de Java que lanzan la excepción que está recibiendo, y su uso no coincide con la descripción que ha proporcionado. – SingleShot

+0

Definitivamente debería usar una cola de bloqueo. JavaDocs para http://java.sun.com/javase/6/docs/api/java/util/concurrent/BlockingQueue.html tiene código de ejemplo. –

Respuesta

3

Su código no inicia un nuevo hilo, ejecuta el ciclo en el mismo hilo y es por eso que obtiene un error de tiempo de espera cuando se implementa.

Para iniciar un hilo, debe llamar al método de inicio, no al método de ejecución.

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

Guau, ¡tienes toda la razón! Lo cambié para comenzar antes con cambiarlo a Daemon thread "solo porque" como dicen y comenzó a funcionar y no me di cuenta de que era debido a eso. (Ahora probé y esto es lo que me estaba deteniendo). Un millón de gracias. – Ittai

+0

Recientemente he cometido el mismo error :-( – Serxipc

+0

Ha! Bien visto. Solo el tipo de cosas que podrían poner en esas tontas pruebas de Java: tienen un fragmento que llama Thread.run() en lugar de Thread.start() y pregunta "¿Qué pasa con este código?" –

0

Tome un vistazo a java.langThread.setDaemon método(), puede que es lo que necesita

3

Esto sería una muy mala idea. Causaría una carga de CPU del 100% sin una buena razón.

La solución correcta es probablemente bloquear el hilo cuando la cola está vacía. Esto se implementa de manera trivial con un BlockingQueue.

+0

y ¿cuál es el tiempo de respuesta para eso? Quiero decir que esto no está implementado con sleep() pero el 'BlockingQueue' en sí mismo despierta el hilo si entiendo correctamente, ¿así de inmediato? – Ittai

+0

El tiempo de respuesta estaría dominado por el programador de hilos del sistema operativo. El hilo de espera está bloqueado en el nivel del sistema operativo. Cuando la cola se llena, se indica el sistema operativo. En ese punto, el hilo se cambia de esperar a ejecutable, y si hay una CPU/núcleo disponible en ese momento, el hilo probablemente se ejecute inmediatamente. Debido a que ha estado esperando, es probable que reciba un aumento de prioridad también. – MSalters

+0

En un sistema de Windows, el tiempo de espera de un bloque podría ser de hasta 10 milisegundos, en un sistema Unix mucho menos. –

5

setDaemon

RESUMEN:

  • Marcas este hilo, ya sea como un hilo daemon o un hilo de usuario.La máquina virtual Java se cierra cuando los hilos únicos que se ejecutan son todos subprocesos de daemon.
  • Este método debe invocarse antes de iniciar la secuencia.
  • Este método llama primero al método checkAccess de este hilo
    sin argumentos. Esto puede ocasionar que arroje una SecurityException (en el
    hilo actual).

Threads

Resumen: En muchos casos, lo que realmente queremos es crear subprocesos de fondo que hacen tareas simples y periódicos en una aplicación . El método setDaemon() se puede utilizar para marcar un subproceso como un subproceso daemon que se debe eliminar y descartar cuando no quedan otros subprocesos de la aplicación . Normalmente, el intérprete de Java continúa ejecutándose hasta que todos los hilos se hayan completado. Pero cuando los hilos daemon son los únicos hilos que siguen vivos, el intérprete saldrá.

+0

Lo siento, no puedo aceptar dos respuestas, pero en realidad tanto usted como MSalters tenían razón, necesitaba corregir ambos errores para que el problema se resolviera. Te di una de todas maneras, gracias por el esfuerzo. – 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. 

"Ese hilo se detiene"? ¿Cómo? No hay una condición de terminación en su ciclo while (verdadero) {...}. ¿Cómo lo estás deteniendo? ¿Estás utilizando el método Thread.stop()? Eso no es seguro y fue obsoleto en Java 1.1

Si usa setDaemon (verdadero), el hilo permanecerá activo después de que haya detenido la aplicación web utilizando las herramientas de administración de su servidor de aplicación. Luego, si reinicias la aplicación web, obtendrás otro hilo. Incluso si intenta anular la implementación de la aplicación web, el hilo seguirá en funcionamiento e impedirá que toda la aplicación web sea recolectada. Luego, volver a desplegar la próxima versión le dará una copia adicional de todo en la memoria.

Si proporciona una condición de salida para el bucle (por ejemplo, InterruptedException o un booleano "stopNow" volátil), puede evitar este problema.

Cuestiones relacionadas