为了账号安全,请及时绑定邮箱和手机立即绑定

在Tomcat中从servlet生成线程的推荐方法是什么

在Tomcat中从servlet生成线程的推荐方法是什么

大话西游666 2019-08-31 11:25:31
可能重复一次!我使用Tomcat作为我的服务器,并想知道什么是在确定性结果的servlet中生成线程的最佳方法。我正在从servlet操作运行一些长时间运行的更新,并希望完成请求并在后台进行更新。而不是添加像RabbitMQ这样的消息中间件,我想我可以生成一个可以在后台运行并在自己的时间内完成的线程。我在其他SO线程中读到服务器终止服务器生成的线程,以便它能够很好地管理资源。在使用Tomcat时是否有推荐的方法来生成线程,后台作业。我还使用Spring MVC作为应用程序。
查看完整描述

3 回答

?
慕仙森

TA贡献1827条经验 获得超8个赞

最安全的做法是使用具有最大线程数量的应用程序宽线程池,以便在必要时将任务排队。这ExecutorService对此很有帮助。


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


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

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


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

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


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


查看完整回答
反对 回复 2019-08-31
?
繁星点点滴滴

TA贡献1803条经验 获得超3个赞

您可以使用像Foo-CommonJ这样的CommonJ WorkManager(JSR 237)实现:


CommonJ - JSR 237定时器和工作管理器

Foo-CommonJ是一个JSR 237 Timer和WorkManager实现。它被设计用于没有自己实现的容器 - 主要是像Tomcat这样的普通servlet容器。它还可以用于没有WorkManager API或具有JBoss等非标准API的完全成熟的Java EE应用程序服务器。


为什么使用WorkManagers?

常见的用例是Servlet或JSP需要聚合来自多个源的数据并在一个页面中显示它们。像J2EE容器那样对自己的线程进行托管环境是不合适的,不应该在应用程序级代码中完成。在这种情况下,WorkManager API可用于并行检索数据。


安装/部署CommonJ

JNDI资源供应商的部署依赖。此实现附带一个实现javax.naming.spi.ObjectFactory 接口的Factory类, 使其可以在最流行的容器中轻松部署。它也可以作为JBoss服务使用。更多...


更新:只是为了澄清,以下是Java EE预览的并发实用程序(看起来像是JSR-236和JSR-237的后续版本)写的关于非托管线程的内容:


2.1容器管理与非管理线程

Java EE应用程序服务器需要资源管理,以便集中管理并保护应用程序组件不会消耗不必要的资源。这可以通过汇集资源和管理资源的生命周期来实现。使用Java SE并发实用程序(如 java.util.concurrencyAPI)  java.lang.Thread以及  java.util.Timer服务器应用程序组件(如servlet或EJB)是有问题的,因为容器和服务器不了解这些资源。


通过扩展  java.util.concurrentAPI, 应用程序服务器和Java EE容器可以了解所使用的资源,并为运行的异步操作提供正确的执行上下文。


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


所以没有新的IMO,“旧”问题是一样的,非托管线程仍然是非托管线程:


它们对于应用程序服务器是未知的,并且无法访问Java EE上下文信息。

他们可以使用应用程序服务器背面的资源,并且没有任何管理能力来控制其数量和资源使用情况,这可能会影响应用程序服务器从故障中恢复资源或正常关闭的能力。


查看完整回答
反对 回复 2019-08-31
?
米琪卡哇伊

TA贡献1998条经验 获得超6个赞

我知道这是一个老问题,但人们一直在问它,试图做这种事情(在处理servlet请求时显式产生线程)一直......这是一个非常有缺陷的方法 - 出于多个原因。 ..简单地说Java EE容器对这种做法不满意是不够的,尽管一般都是......


最重要的是,人们永远无法预测servlet在任何给定时间将接收多少并发请求。根据定义,Web应用程序,servlet意味着能够一次处理给定端点上的多个请求。如果您正在编程请求处理逻辑以显式启动一定数量的并发线程,那么您可能面临一个完全不可避免的情况,即可用线程耗尽并阻塞您的应用程序。您的任务执行程序始终配置为使用限制为有限合理大小的线程池。大多数情况下,它不大于10-20(你不需要太多线程执行你的逻辑 - 取决于任务的性质,他们竞争的资源,服务器上的处理器数量等)让我们说,你的请求处理程序(例如 MVC控制器方法)调用一个或多个@Async-annotated方法(在这种情况下,Spring抽象任务执行程序并使事情变得简单)或明确使用任务执行程序。当您的代码执行时,它开始从池中获取可用的线程。如果您总是一次处理一个请求而没有立即的后续请求,那就没问题。(在这种情况下,您可能正在尝试使用错误的技术来解决您的问题。)但是,如果它是一个Web应用程序,它暴露给任意(甚至已知)客户端可能正在通过请求锤击端点,您将快速耗尽线程池,请求将开始堆积,等待线程可用。仅仅因为这个原因,你应该意识到你可能走错了路 - 如果你正在考虑这样的设计。当您的代码执行时,它开始从池中获取可用的线程。如果您总是一次处理一个请求而没有立即的后续请求,那就没问题。(在这种情况下,您可能正在尝试使用错误的技术来解决您的问题。)但是,如果它是一个Web应用程序,它暴露给任意(甚至已知)客户端可能正在通过请求锤击端点,您将快速耗尽线程池,请求将开始堆积,等待线程可用。仅仅因为这个原因,你应该意识到你可能走错了路 - 如果你正在考虑这样的设计。当您的代码执行时,它开始从池中获取可用的线程。如果您总是一次处理一个请求而没有立即的后续请求,那就没问题。(在这种情况下,您可能正在尝试使用错误的技术来解决您的问题。)但是,如果它是一个Web应用程序,它暴露给任意(甚至已知)客户端可能正在通过请求锤击端点,您将快速耗尽线程池,请求将开始堆积,等待线程可用。仅仅因为这个原因,你应该意识到你可能走错了路 - 如果你正在考虑这样的设计。)但是,如果它是一个Web应用程序,它暴露给任意(甚至已知)客户端可能正在通过请求锤击端点,您将很快耗尽线程池,并且请求将开始堆积,等待线程成为可用。仅仅因为这个原因,你应该意识到你可能走错了路 - 如果你正在考虑这样的设计。)但是,如果它是一个Web应用程序,它暴露给任意(甚至已知)客户端可能正在通过请求锤击端点,您将很快耗尽线程池,并且请求将开始堆积,等待线程成为可用。仅仅因为这个原因,你应该意识到你可能走错了路 - 如果你正在考虑这样的设计。


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


查看完整回答
反对 回复 2019-08-31
  • 3 回答
  • 0 关注
  • 366 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号