2009-09-10 9 views
5

EDIT: Je suis maintenant sûr que le problème est lié à la boucle while (true) maintenant toutes les autres commandes comme je l'ai commenté et l'application déploie sans l'exception jointe. Je ne sais pas combien il est important, mais ma mise en œuvre ServletContextListener ressemble à ceci:Comment créer un thread qui s'exécute tout le temps que mon application est en cours

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

Alors maintenant, le fil est exécuté lorsque l'application est déployée, mais parce que la boucle while est commenté, il n'a pas de sens réel .

Je dois avoir un thread en arrière-plan lorsque mon application se charge et constamment (sans timeout) vérifier une certaine file d'attente pour les objets. Bien sûr, une fois qu'il y a des objets, il "prend soin d'eux" et continue ensuite à vérifier la file d'attente.

Actuellement, j'implémente l'interface ServletContextListener et on m'appelle quand l'application se charge. Dans celui-ci, je fais quelques choses de maintenance et commence un fil dont j'ai hérité de java.lang.Thread.

Voici où commence mon problème (ou je pense). Dans ma méthode run(), j'ai un

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

Lorsque je tente de déployer mon application sur le serveur je reçois un java.util.concurrent.TimeOutException. Qu'est-ce que je fais de mal?

Impossible d'avoir un thread qui est toujours en cours d'exécution? Lorsque l'application est supprimée, ce thread est arrêté par l'événement correspondant dans mon ServletContextListener.

J'ai vraiment besoin de quelque chose qui continue à vérifier la file d'attente sans délai.

Merci beaucoup pour toute aide!

Edit: Ceci est la trace de la pile

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) 

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

Désolé pour le désordre de mise en forme, mais pour la vie de mon "code tiret par 4 espaces" ne fonctionne pas pour moi Editer: Lire à propos de 'BlockingQueue' et l'implémenter, mais je reçois toujours la même exception et trace de la pile. modifié le code ci-dessus pour tenir compte de l'utilisation de « BlockingQueue »

+0

Vous devrez nous donner la trace de la pile de l'exception – skaffman

+0

Veuillez montrer votre code. Il y a très peu de classes dans l'API Java qui lancent l'exception que vous recevez, et leur utilisation ne correspond pas à la description que vous avez fournie. – SingleShot

+0

Vous devriez certainement utiliser une file d'attente de blocage. Les JavaDocs pour http://java.sun.com/javase/6/docs/api/java/util/concurrent/BlockingQueue.html ont un exemple de code. –

Répondre

3

Votre code ne démarre pas un nouveau sujet, il exécute la boucle dans le même thread et c'est pourquoi vous obtenez une erreur de délai d'attente lors du déploiement. Pour démarrer un thread, vous devez appeler la méthode start, pas la méthode 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(); 
} 
+0

Wow, vous avez absolument raison! Je l'ai changé pour commencer plus tôt en le changeant en fil de démon "juste parce que" comme ils disent et cela a commencé à fonctionner et je ne me suis pas rendu compte que c'était dû à cela. (J'ai maintenant testé et c'est ce qui m'arrêtait). Merci un million. – Ittai

+0

J'ai récemment fait la même erreur :-( – Serxipc

+0

Ha! Eh bien repéré juste le genre de chose qu'ils pourraient mettre dans ces tests Java idiots: avoir un extrait qui appelle Thread.run() au lieu de Thread.start() et demandez "Qu'est-ce qui ne va pas avec ce code?" –

0

Jetez un oeil à la méthode java.langThread.setDaemon(), il est peut ce que vous avez besoin

3

Ce serait une très mauvaise idée. Vous pourriez provoquer une charge de 100% du processeur sans raison valable.

La solution correcte est probablement de bloquer le thread lorsque la file d'attente est vide. Ceci est implémenté de manière triviale avec un BlockingQueue.

+0

et quel est le temps de réponse pour cela? Je veux dire que ceci n'est pas implémenté avec sleep() mais le 'BlockingQueue' lui-même réveille le fil si je comprends bien, donc est-ce immédiat? – Ittai

+0

Le temps de réponse serait dominé par le planificateur de thread OS. Le thread en attente est bloqué au niveau de l'OS. Lorsque la file d'attente est remplie, le système d'exploitation est signalé. À ce stade, le thread passe de l'attente à l'exécution, et si un CPU/core est disponible à ce moment-là, le thread est probablement exécuté immédiatement. Parce qu'il a été en attente, il aura probablement un coup de pouce de priorité, aussi. – MSalters

+0

Sur un système Windows, le temps d'attente d'un bloc peut atteindre 10 millisecondes, sur un système unix beaucoup moins. –

5

setDaemon

RÉSUMÉ:

  • Marks ce fil soit comme un thread démon ou d'un fil d'utilisateur.La machine virtuelle Java se ferme lorsque les threads exécutés sont tous des threads daemon.
  • Cette méthode doit être appelée avant le démarrage du thread.
  • Cette méthode appelle d'abord la méthode checkAccess de ce thread
    sans argument. Cela peut entraîner lançant une exception SecurityException (dans le thread actuel
    ).

Threads

RÉSUMÉ: Dans de nombreux cas, ce que nous avons vraiment voulons est de créer des fils de fond qui ne simples, des tâches périodiques dans une application . La méthode setDaemon() peut être utilisée pour marquer un thread en tant que thread de démon qui doit être supprimé et supprimé en l'absence d'autres threads d'application . Normalement, l'interpréteur Java continue d'exécuter jusqu'à ce que tous les threads soient terminés. Mais lorsque les threads de démon sont les seuls threads encore en vie, l'interpréteur va quitter.

+0

Je suis désolé je ne peux pas accepter deux réponses, mais en réalité vous et MSalters avaient raison, je devais corriger les deux erreurs afin que le problème soit résolu. Je vous en ai donné une de toute façon, merci pour l'effort. – 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. 

"Ce fil est arrêté"? Comment? Il n'y a pas de condition de terminaison dans votre boucle while (true) {...}. Comment l'arrêtez-vous? Utilisez-vous la méthode Thread.stop()? Si vous utilisez setDaemon (true), le thread reste actif après l'arrêt de l'application Web à l'aide des outils de gestion de votre serveur d'applications. Ensuite, si vous redémarrez l'application Web, vous obtiendrez un autre thread. Même si vous tentez de ne pas déployer l'application Web, le thread restera actif et empêchera toute l'application Web d'être récupérée. Puis redéployer la prochaine version vous donnera une copie supplémentaire de tout en mémoire.

Si vous fournissez une condition de sortie pour la boucle (par exemple InterruptedException ou un booléen volatile "stopNow"), vous pouvez éviter ce problème.

Questions connexes