【问题标题】:How to create a thread that runs all the time my application is running如何创建一个在我的应用程序运行时一直运行的线程
【发布时间】:2010-11-27 02:05:58
【问题描述】:

编辑: 我现在确定问题与 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'的使用

【问题讨论】:

  • 您需要向我们提供异常的堆栈跟踪
  • 请出示您的代码。 Java API 中很少有类会抛出您收到的异常,并且它们的使用与您提供的描述不符。
  • 您绝对应该使用阻塞队列。 java.sun.com/javase/6/docs/api/java/util/concurrent/… 的 JavaDocs 有示例代码。

标签: java multithreading deployment servlets timeout


【解决方案1】:

setDaemon

总结:

  • 将此线程标记为守护线程或用户线程。这 Java 虚拟机在 只有运行的线程都是守护进程 线程。
  • 必须在线程启动之前调用此方法。
  • 该方法首先调用该线程的checkAccess方法
    没有论据。这可能会导致 抛出 SecurityException(在
    当前线程)。

Threads

总结:在很多情况下,我们真正 想要的是创建后台线程 做简单的、周期性的任务 应用。 setDaemon() 方法 可用于将 Thread 标记为 应该被杀死的守护线程 并在没有其他人时丢弃 应用程序线程仍然存在。一般, Java 解释器继续运行 直到所有线程都完成。但 当守护线程是唯一的 线程还活着,解释器 将退出。

【讨论】:

  • 很抱歉我不能接受两个答案,但实际上你和 MSalters 都是对的,我需要修复两个错误才能解决问题。反正我给了你一个,谢谢你的努力。
【解决方案2】:

您的代码不会启动新线程,而是在同一个线程中运行循环,这就是您在部署时遇到超时错误的原因。

要启动线程,您必须调用 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 测试中使用的东西:有一个调用 Thread.run() 而不是 Thread.start() 的 sn-p 并询问“这段代码有什么问题?”
【解决方案3】:

这将是一个非常糟糕的主意。你会在没有充分理由的情况下导致 100% 的 CPU 负载。

正确的解决方案可能是在队列为空时阻塞线程。这可以通过BlockingQueue 轻松实现。

【讨论】:

  • 那么响应时间是多少?我的意思是这不是用 sleep() 实现的,但如果我理解正确,'BlockingQueue' 本身会唤醒线程,那是立即的吗?
  • 响应时间将由操作系统线程调度程序控制。等待线程在操作系统级别被阻塞。当队列被填满时,向操作系统发出信号。此时线程从等待变为可运行,如果此时有可用的 CPU/内核,则线程可能会立即运行。因为它一直在等待,所以它也可能会获得优先级提升。
  • 在 Windows 系统上,从一个块等待的时间可能长达 10 毫秒,而在 unix 系统上则更少。
【解决方案4】:
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),则在您使用应用服务器的管理工具停止 Web 应用后,该线程将保持活动状态。然后,如果您重新启动网络应用程序,您将获得另一个线程。即使您尝试取消部署 Web 应用程序,该线程仍将保持运行并防止整个 Web 应用程序被垃圾收集。然后重新部署下一个版本将为您提供内存中所有内容的额外副本。

如果您为循环提供退出条件(例如 InterruptedException 或易失性“stopNow”布尔值),则可以避免此问题。

【讨论】:

    【解决方案5】:

    看看java.langThread.setDaemon()方法,可能是你需要的

    【讨论】:

      猜你喜欢
      • 2021-11-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多