Pergunta

EDIT: Agora estou certo de que o problema está relacionado com o laço while (true) segurando todos os outros comandos como já comentado para fora e as implanta aplicativos sem exceção anexada. Eu não tenho certeza quanto é importante, mas meus ServletContextListener implementação esta aparência:

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

Então, agora o segmento é executado quando o aplicativo é implantado, mas porque o loop while é comentado que não tem nenhum significado real.

Eu preciso ter uma corrida segmento em segundo plano quando meus aplicativo carrega e constantemente (sem limite de tempo) verificar uma certa fila para objetos. Claro, uma vez que existem objetos, ele "cuida deles" e, em seguida, continua a verificar a fila.

Atualmente, estou implementando a interface ServletContextListener e eu estou sendo chamado quando as cargas de aplicativos. Nele, eu faço algumas coisas de manutenção e iniciar uma discussão que eu herdei de java.lang.Thread.

Aqui é onde o meu problema começa (ou então eu acho). No meu método run(), eu tenho um

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

Quando tento implantar o meu aplicativo para o servidor eu recebo um java.util.concurrent.TimeOutException. O que estou fazendo de errado?

Eu não posso ter uma discussão que está sempre correndo? Quando o aplicativo é removido, esse segmento é interrompido pelo evento correspondente na minha ServletContextListener.

Eu realmente preciso de algo que continua a verificar a fila sem demora.

Muito obrigado por qualquer ajuda!

Edit: Este é o rastreamento de pilha

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)

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

Desculpe pela confusão formatação mas para a vida do meu "código travessão por 4 espaços" simplesmente não funciona para mim Edit: Leia sobre 'BlockingQueue' e implementado, mas ainda estou recebendo exatamente a mesma exceção e pilha vestígios. mudou o código acima para refletir o uso de 'BlockingQueue'

Foi útil?

Solução

Seu código não iniciar um novo tópico, corre-se o ciclo na mesma linha e é por isso que você está recebendo um erro de tempo limite quando implantado.

Para iniciar uma discussão você deve chamar o método start, não o método de execução.

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

Outras dicas

setDaemon

RESUMO:

  • Marcas esta discussão tanto como um fio daemon ou um segmento do usuário. o Java Virtual Machine sai quando o apenas threads em execução são todos daemon tópicos.
  • Este método deve ser chamado antes que o segmento é iniciado.
  • Este método primeiro chama o método checkAccess deste segmento
    sem argumentos. Isso pode resultar em jogando um SecurityException (no
    thread atual).

Threads

RESUMO: Em muitos casos, o que realmente falta é criar threads em segundo plano que fazer tarefas simples, periódicas em um inscrição. O () método setDaemon pode ser usado para marcar um segmento como um fio daemon que deve ser morto e descartados quando nenhuma outra threads da aplicação permanecem. Normalmente, o intérprete Java continua a funcionar até que todos os tópicos foram concluídos. Mas quando daemon tópicos são a única tópicos ainda vivo, o intérprete vai sair.

Esta seria uma idéia muito ruim. Você iria provocar uma carga de CPU de 100%, sem uma boa razão.

A solução correcta é provavelmente a bloquear o fio quando a fila está vazia. Esta é trivialmente implementado com um 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.

"Esse segmento está parado"? Quão? Não há condição de término em sua while (true) {...} loop. Como você está parando-o? Você está usando o método Thread.stop ()? Que é inseguro e foi depreciado caminho de volta em Java 1.1

Se você usar setDaemon (true), o fio vai ficar ativo depois de ter parado o web-app usando ferramentas de gerenciamento de seu aplicativo no servidor. Então, se você reiniciar o web-app, você vai ter outro segmento. Mesmo se você tentar undeploy o web-app, o fio vai ficar correndo e impedirá toda a web-app seja coletado como lixo. Em seguida, reimplantar a próxima versão irá dar-lhe uma cópia adicional de tudo na memória.

Se você fornecer uma condição de saída para o loop (por exemplo InterruptedException ou um volátil booleano "stopNow"), você pode evitar esse problema.

Dê uma olhada java.langThread.setDaemon () método, pode é o que você precisa

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top