什么是推荐的方式从Tomcat的servlet产生线程

可能是重复! 我正在使用Tomcat作为我的服务器,并且想知道在servlet中产生具有确定性结果的线程的最佳方法。 我正在从一个servlet动作运行一些长时间运行的更新,并希望完成请求并在后台执行更新。 而不是像RabbitMQ那样添加一个消息中间件,我想我可以生成一个可以在后台运行的线程,并在自己的时间内完成。 我在其他SO线程中读取服务器终止服务器产生的线程,以便它能够很好地pipe理资源。

有没有推荐的方式来产生线程,使用Tomcat的后台作业。 我也使用Spring MVC的应用程序。

最安全的方法是使用线程池数量最多的应用程序线程池 ,以便在必要时将任务排队。 ExecutorService在这方面非常有帮助。

在应用程序启动或servlet初始化时,使用Executors类:

 executor = Executors.newFixedThreadPool(10); // Max 10 threads. 

然后在servlet的服务期间(你可以忽略你不感兴趣的情况):

 Future<ReturnType> result = executor.submit(new CallableTask()); 

最后,在应用程序的closures或servlet的销毁期间:

 executor.shutdownNow(); // Returns list of undone tasks, for the case that. 

您可以使用CommonJ WorkManager(JSR 237)实现,如Foo-CommonJ :

CommonJ – JSR 237定时器和工作pipe理器

Foo-CommonJ是一个JSR 237定时器和WorkManager实现。 它被devise用于不带有自己的实现的容器 – 主要是像Tomcat这样的简单的servlet容器 。 它也可以用于没有WorkManager API或者具有非标准API(如JBoss)的完整Java EE应用程序服务器。

为什么使用WorkManagers?

常见的用例是Servlet或JSP需要汇集来自多个源的数据并将其显示在一个页面中。 像J2EE容器一样执行自己的线程化托pipe环境是不合适的,不应该在应用程序级代码中完成 。 在这种情况下,WorkManager API可以用来并行检索数据。

安装/部署CommonJ

依赖于JNDI资源的部署。 这个实现带有一个Factory类,它实现了javax.naming.spi.ObjectFactory接口,使它可以在最stream行的容器中轻松部署。 它也可以作为一个JBoss服务。 更多…

更新:为了澄清,下面是Java EE Preview的并发实用程序 (看起来像是JSR-236和JSR-237的后继者)写的关于非托pipe线程的内容:

2.1容器pipe理与非pipe理线程

Java EE应用程序服务器需要进行资源pipe理,以便集中pipe理并保护应用程序组件免于使用不必要的资源。 这可以通过汇集资源和pipe理资源的生命周期来实现。 在服务器应用程序组件(如servlet或EJB)中使用Java SE并发实用程序(如java.util.concurrency API, java.lang.Threadjava.util.Timer有问题的,因为容器和服务器不知道这些资源

通过扩展java.util.concurrent API, 应用程序服务器和Java EE容器可以意识到所使用的资源,并为asynchronous操作提供正确的执行上下文

这主要通过提供主要的java.util.concurrent.ExecutorService接口的pipe理版本来实现。

所以没有什么新的IMO,“老”问题是一样的,非托pipe线程仍然是非托pipe线程:

  • 它们对于应用程序服务器是未知的,并且不能访问Java EE上下文信息。
  • 他们可以使用应用程序服务器背后的资源,并且没有任何pipe理能力来控制其数量和资源使用情况,这可能会影响应用程序服务器从故障中恢复资源或正常closures的能力。

参考

  • Java EE兴趣站点的并发实用程序
  • Java EE预览版的并发实用程序 (PDF)

Spring通过弹簧调度支持asynchronous任务(在你的情况下长时间运行)。 我不build议直接使用Java线程,而是使用Quartz。

追索权:

  • 春季参考:第23章

严格来说,根据Java EE规范,不允许产生线程。 如果同时发出多个请求,我还会考虑拒绝服务攻击的可能性(故意或其他)。

一个中间件解决scheme肯定会更健壮和符合标准。

我知道这是一个古老的问题,但人们不停地问,试图做这种事情(显式产生线程,同时处理一个servlet请求)…这是一个非常有缺陷的方法 – 由于不止一个原因。简单地说,Java EE容器在这样的实践中皱眉头是不够的,虽然通常是真实的…

最重要的是,人们永远无法预测servlet在任何给定的时间将接收到多less个并发请求。 一个Web应用程序,一个servlet,根据定义,意味着能够一次处理给定端点上的多个请求。 如果您正在编程请求处理逻辑以显式启动一定数量的并发线程,那么您将冒着面临用尽线程和窒息应用程序的所有不可避免情况的风险。 您的任务执行程序始终configuration为使用限制在合理大小的线程池。 大多数情况下,它不大于10-20(你不希望太多的线程执行你的逻辑 – 这取决于任务的性质,它们竞争的资源,服务器上的处理器数量等)。 ,您的请求处理程序(例如MVC控制器方法)会调用一个或多个@ Async注释的方法(在这种情况下,Spring将抽象任务执行程序并使事情变得容易)或明确使用任务执行程序。 当你的代码执行时,它开始从池中获取可用的线程。 如果你总是一次处理一个请求而没有立即的后续请求,那就没问题了。 (在这种情况下,您可能试图使用错误的技术来解决您的问题。)但是,如果这是一个Web应用程序暴露给任意(甚至已知)客户端,可能正在敲击端点的请求,快速消耗线程池,请求将开始堆积,等待线程可用。 仅仅因为这个原因,你应该意识到,如果你正在考虑这样的devise,你可能会走上一条错误的道路。

一个更好的解决scheme可能是将要asynchronous处理的数据(可能是一个队列或任何其他types的临时/暂存数据存储)进行处理并返回响应。 有一个外部独立应用程序,甚至是多个实例(部署在您的Web容器之外)轮询分段端点并在后台处理数据,可能使用有限数量的并发线程。 这样的解决scheme不仅可以为您提供asynchronous/并发处理的优势,而且还可以扩展,因为您可以根据需要运行这样的轮询器的多个实例,并且可以分发它们,指向分段terminal。 HTH

自Spring 3以来,您可以使用@Async注释:

 @Service public class smg { ... @Async public getCounter() {...} } 

<context:component-scan base-package="ch/test/mytest">使用<context:component-scan base-package="ch/test/mytest"><task:annotation-driven/>

请参阅本教程: http : //spring.io/blog/2010/01/05/task-scheduling-simplifications-in-spring-3-0/

在Tomcat7上对我很好,你不必pipe理一个线程池。