2014-09-29 104 views
0

在阅读了很多不同的东西并且完全不熟悉这些东西中的正确术语之后,我想知道在创建线程时正确的方式是什么tomcat启动特定用途。我正在使用一个linux系统。在启动时在tomcat中创建任务线程的正确方法

我不想从一个servlet创建一个线程,并且我对这个不好的原因有个好主意。当tomcat启动时,我想要两个不同的线程有独特的目的开始。第一个线程每隔30分钟运行一次,以审计后端数据。第二个线程负责发送电子邮件。当请求运行一个必须发送电子邮件的servlet时,我不想阻止等待发送电子邮件的servlet,而是要发送一个请求到这个电子邮件线程并继续前进。所以一个定期运行,一个按需运行。我从来不需要增加执行这些任务的线程数,我只需要这两个就可以了,只要webapp正在运行,并且如果webapp必须停止,我就不会在意曼妙关掉。

有我知道我可以采取一些办法:

  1. 以外的tomcat创建运行的过程和定义的方式与我的servlet这一进程进行通信。如果可能的话,我想避免这种情况,因为我希望这两个线程首先直接与启动和关闭Web应用程序相关联,并且他们能够访问ServletContext中的数据,而不是必须通过通信通道传送/接收数据。

  2. 在我的一个servlet的init方法中产生两个线程。这看起来很肮脏和黑客,但它肯定会完成工作。

  3. 创建一个ServletContextListener,它扩展了ThreadPoolExecutor或其他ExexutorService。这似乎有吸引力和正确的,我想我可以做一个固定的2线程线程池,因为我不需要更多。但是,这是推荐的方式来做我想要的吗?据我所知,ExecutorService实际上更适用于执行Runnable,而不必失去创建线程的开销。我不知道这是否完全正确,但如果是这样,我不会为了其目的而使用执行者。

也许有更多的方法,我不知道或实现上述之一的正确方法。

+2

首先,**这与Tomcat **无关,请编辑该问题。你的问题是你如何在_web application_中启动服务线程。其次,你的第三种方法几乎是正确的 - 但不要“扩展”,这当然是错误的。另外,考虑两个听众,因为这些听众似乎是各自关心的问题,将他们分组在一起也是一种骇客。确保你理解并使用'ScheduledExecutorService'并确保你正确关闭你的执行程序。 – 2014-09-29 13:45:14

+0

听起来像你真正想要的是两个[Singleton](http://stackoverflow.com/q/70689/823393)s。 – OldCurmudgeon 2014-09-29 14:08:24

+0

关于这个与tomcat无关的问题,我特别提到了tomcat,因为我会尝试在WebSphere中使用'WorkManager'来做这样的事情,并且我会将'Work'传递给它。我不相信Tomcat本身具有这种能力(尽管我认为JBOSS可能),所以我特别对像Tomcat这样的轻量级servlet处理器的选择感兴趣。 – 2014-09-29 18:29:05

回答

1

请参考以下Q & A:tomcat 6 thread pool for asynchronous processing

此外,您可能需要Executors.newScheduledThreadPool来创建ScheduledExecutorService的实例,该实例能够执行重复任务。

希望这有助于...

+0

为单一按需线程使用'Executors.newFixedThreadPool'和为我的定期任务使用'Executors.newScheduledThreadPool'是否有意义?仅仅选择一个线程会更有意义,例如,两个线程都使用'fixedThreadPool',并将我的周期性任务调整到这个线程上? (正如在使用'Thread.sleep(30分钟)''以确保周期?) – 2014-09-29 17:49:42

+1

@MichaelPlautz不要使用相同的池的两个任务,因为这两个任务是完全无关的(从你描述他们的方式)。而且从来没有**使用Thread.sleep - 如果你正在考虑使用它,那么你正在做的事情非常错误。 – 2014-09-30 07:42:20

+0

@MichaelPlautz我完全同意'Boris the Spider' - **从来没有**使用Thread.sleep **或类似的方法,因为它是**在Java中使用多线程的低级方式,应该是仅**使用**如果需要使用** ExecutorService **和/或** ScheduledExecutorService **无法实现的非常特定的多线程逻辑,它们被视为**高级**(因此**更少的错误倾向**)在Java中使用多线程的方式。 – Yura 2014-09-30 08:58:33

1

我不会去执行线程池本身,而是取决于你的问题:

正确的方式在启动

建立在Tomcat的任务线程的人说,你的第三个方法几乎是正确的但是这取决于您的服务结构。

我给你举个例子,然后解释:

public class YourServletContextListener implements ServletContextListener{  
    @Override 
    public void contextDestroyed(ServletContextEvent sce) { 

    }   
    @Override 
    public void contextInitialized(ServletContextEvent sce) { 

    } 
} 

从文档:

contextInitialized: 

所有的ServletContextListener通知上下文初始化的 任何过滤器或servlet之前在web应用程序中初始化为

如果我正确理解你的方法,那么我会问你:你想如何启动一个服务或发送任何请求到一个尚未初始化的servlet?

如果您想要启动的服务不直接与Web应用程序进行通信/需要任何servlet或过滤器或任何数据,这将起作用。稍后,在启动容器后,他们可以确保相互通信。

正如我之前所说,最好使用哪种方式取决于服务结构/逻辑。

一种其他方法可被使用的过滤器:

void init(FilterConfig filterConfig) throws ServletException 

由web容器调用以指示它正在 投入使用的过滤器。在实例化过滤器后,servlet容器仅调用一次init方法 。

void destroy() 

由web容器调用以指示它正在 退出服务的过滤器。只有在过滤器的doFilter方法中的所有线程 已退出或超过 时间段过去后才调用此方法。在Web容器调用此方法后,它将在此过滤器实例上不会再次调用doFilter方法 。

此方法使过滤器清理的任何资源 正在举行的(例如,内存,文件句柄,线程)和 确保任何持久性状态与内存中的过滤器的 当前状态同步的机会。

但过滤器不是为这种方法而设计的!

,如果你想拦截的MACHING一个 特定的URL模式,因为要检查/修改HTTP 请求/响应HTTP请求使用过滤器。如果您希望 在webapp的启动和/或关闭时截获,请使用ServletContextListener。

相关问题