Как создать поток, который выполняется все время, пока работает мое приложение

StackOverflow https://stackoverflow.com/questions/1403755

Вопрос

Редактировать:Теперь я уверен, что проблема связана с while (true) цикл содержит все остальные команды в том виде, в каком я их прокомментировал, и приложение развертывается без прикрепленного исключения.Я не уверен, насколько это важно, но мой ServletContextListener реализация выглядит примерно так:

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

Итак, теперь поток запускается при развертывании приложения, но поскольку while цикл прокомментирован, он не имеет никакого реального значения.

Мне нужно, чтобы поток запускался в фоновом режиме при загрузке моего приложения и постоянно (без таймаута) проверял определенную очередь на наличие объектов.Конечно, как только появляются объекты, он "заботится о них", а затем продолжает проверять очередь.

В настоящее время я внедряю ServletContextListener интерфейс, и меня вызывают, когда загружается приложение.В нем я выполняю несколько операций по обслуживанию и запускаю поток, который я унаследовал от java.lang.Thread.

Вот тут-то и начинается моя проблема (по крайней мере, я так думаю).В моем run() метод, у меня есть

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

Когда я пытаюсь развернуть свое приложение на сервере, я получаю java.util.concurrent.TimeOutException.Что я делаю не так?

Разве у меня не может быть потока, который всегда запущен?Когда приложение удаляется, этот поток останавливается соответствующим событием в моем ServletContextListener.

Мне действительно нужно что-то, что продолжает проверять очередь без задержек.

Большое спасибо за любую помощь!

Редактировать:Это трассировка стека

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)

Мой Код:

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

Извините за беспорядок форматирования, но в течение всего срока службы мой "отступ в коде на 4 пробела" просто не работает для меня Редактировать:Прочитал о 'BlockingQueue' и реализовал его, но я все еще получаю точно такое же исключение и трассировку стека.изменен приведенный выше код, чтобы отразить использование 'BlockingQueue'

Это было полезно?

Решение

Ваш код не запускает новый поток, он запускает цикл в том же потоке, и именно поэтому вы получаете ошибку тайм-аута при развертывании.

Чтобы запустить поток, вы должны вызвать метод start, а не метод 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();
}

Другие советы

Сетдэмон

Краткие сведения:

  • Помечает этот поток либо как поток демона, либо как пользовательский поток. Виртуальная машина Java завершает работу, когда выполняются только все потоки daemon потоки.
  • Этот метод должен быть вызван до запуска потока.
  • Этот метод сначала вызывает метод checkAccess этого потока
    без всяких аргументов.Это может привести к возникновению исключения SecurityException (в
    текущий поток).

Ветки

Краткие сведения:Во многих случаях, что мы действительно хочу создать фоновых потоков что делать простой, периодические задачи в приложение.Метод setDaemon() может использоваться для пометки потока как потока демона, который должен быть уничтожен и отброшен, когда не останется других потоков приложения.Обычно, интерпретатор Java продолжает выполняться до тех пор, пока все потоки не завершатся.Но когда потоки демона являются единственными все еще активными потоками, интерпретатор завершит работу.

Это было бы очень плохой идеей.Вы бы вызвали 100%-ную загрузку процессора без уважительной причины.

Правильное решение, вероятно, состоит в том, чтобы заблокировать поток, когда очередь пуста.Это тривиально реализовано с помощью 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.

"Эта нить остановлена"?Каким образом?В вашем цикле while (true) {...} нет условия завершения.Как ты это останавливаешь?Используете ли вы метод Thread.stop()?Это небезопасно и устарело еще в Java 1.1

Если вы используете setDaemon (true), поток останется активным после того, как вы остановите веб-приложение с помощью инструментов управления вашего сервера приложений.Затем, если вы перезапустите веб-приложение, вы получите другой поток.Даже если вы попытаетесь отменить развертывание веб-приложения, поток останется запущенным и предотвратит сбор мусора во всем веб-приложении.Затем повторное развертывание следующей версии даст вам дополнительную копию всего, что есть в памяти.

Если вы предоставляете условие выхода для цикла (напримерInterruptedException или изменчивое логическое значение "stopNow"), вы можете избежать этой проблемы.

Взгляните на метод java.langThread.setDaemon(), возможно, это то, что вам нужно

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top