如何创建一个在我的应用程序运行时一直运行的线程

编辑:我现在确定问题与while (true)循环有关,因为我已经注释了所有其他命令并且应用程序在没有附加exception的情况下进行部署。 我不确定它有多重要,但我的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.Threadinheritance的线程。

这是我的问题开始的地方(或者我认为)。 在我的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> aucWatchers = (Map<String, List>) sc.getAttribute("aucWatchers"); BlockingQueue aucBids = (BlockingQueue) 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 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’并实现它,但我仍然得到完全相同的exception和堆栈跟踪。 更改了上面的代码以反映’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(); } 

setDaemon

概要:

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

主题

总结:在许多情况下,我们真正想要的是创建在应用程序中执行简单的定期任务的后台线程。 setDaemon()方法可用于将Thread标记为守护程序线程,当没有其他应用程序线程保留时,该守护程序线程应该被终止并被丢弃。 通常,Java解释器继续运行,直到所有线程都完成。 但是当守护程序线程是唯一仍处于活动状态的线程时,解释器将退出。

这将是一个非常糟糕的主意。 如果没有充分的理由,您将导致100%的CPU负载。

正确的解决方案可能是在队列为空时阻塞线程。 这可以通过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),则在使用app-server的管理工具停止Web应用程序后,该线程将保持活动状态。 然后,如果您重新启动Web应用程序,您将获得另一个线程。 即使您尝试取消部署Web应用程序,该线程仍将继续运行,并将阻止整个Web应用程序被垃圾回收。 然后重新部署下一个版本将为您提供内存中所有内容的附加副本。

如果为循环提供退出条件(例如InterruptedException或volatile“stopNow”boolean),则可以避免此问题。

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