可能重复一次!我使用Tomcat作为我的服务器,并想知道什么是在确定性结果的servlet中生成线程的最佳方法。我正在从servlet操作运行一些长时间运行的更新,并希望完成请求并在后台进行更新。而不是添加像RabbitMQ这样的消息中间件,我想我可以生成一个可以在后台运行并在自己的时间内完成的线程。我在其他SO线程中读到服务器终止服务器生成的线程,以便它能够很好地管理资源。
使用Tomcat时是否有推荐的方法来生成线程,后台作业。我还使用Spring MVC作为应用程序。
答案 0 :(得分:43)
您最安全的选择是使用具有最大线程数量的应用程序宽线程池,以便在必要时将任务排队。 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.
答案 1 :(得分:30)
您可以使用像Foo-CommonJ这样的CommonJ WorkManager(JSR 237)实现:
CommonJ - JSR 237计时器&amp;的WorkManager
Foo-CommonJ是一个JSR 237计时器和 WorkManager实现。 是的 设计用于容器 不要自己来 实现 - 主要是普通的servlet 容器如Tomcat 。它也可以 用于完全成熟的Java EE应用程序 没有WorkManager的服务器 API或具有非标准API JBoss的。
为什么使用WorkManagers?
常见的用例是Servlet 或JSP需要聚合来自的数据 多个来源并显示它们 一页。 做自己的线程a 像J2EE一样管理环境 容器是不合适的,应该 永远不要在应用程序级别完成 代码即可。在这种情况下是WorkManager API 可用于检索数据 平行。
安装/部署CommonJ
部署JNDI资源 供应商依赖。这个实现 附带一个Factory类 实现
javax.naming.spi.ObjectFactory
界面使它变得容易 可部署在最受欢迎的 容器。它也可以作为 JBoss服务。更...
更新:为了澄清,这里是Concurrency Utilities for Java EE Preview(看起来这是JSR-236&amp; JSR-237的继承者)写的关于非托管线程的内容:
2.1容器管理与非管理线程
Java EE应用程序服务器 需要按顺序进行资源管理 集中管理和 保护应用程序组件 消耗不需要的资源。这个可以 通过汇集来实现 资源和管理资源 生命周期。使用Java SE并发 公用事业,如
java.util.concurrency
API,java.lang.Thread
和 服务器中的java.util.Timer
应用程序组件,如 servlet或EJB是有问题的 容器和服务器没有 了解这些资源。通过扩展
java.util.concurrent
API, 应用程序服务器和Java EE 容器可以意识到 使用和提供的资源 正确的执行上下文 使用运行的异步操作。这主要是通过提供来实现的 托管版本的主导
java.util.concurrent.ExecutorService
接口
所以没有新的IMO,“旧”问题是一样的,非托管线程仍然是非托管线程:
答案 2 :(得分:7)
Spring通过spring-scheduling支持异步任务(在你的情况下长时间运行)。我建议不要直接使用Java线程,而是使用Quartz。
<强>资源述略:强>
答案 3 :(得分:4)
严格地说,根据Java EE规范,不允许生成线程。如果有多个请求同时进入,我还会考虑拒绝服务攻击(故意或其他方式)的可能性。
中间件解决方案肯定会更强大且符合标准。
答案 4 :(得分:4)
我知道这是一个老问题,但人们一直在问它,试图做这种事情(在处理servlet请求时显式产生线程)一直......这是一个非常有缺陷的方法 - 对于超过一个原因......简单地说Java EE容器对这种做法不满意是不够的,尽管通常都是正确的......
最重要的是,人们无法预测servlet在任何给定时间将接收多少并发请求。根据定义,Web应用程序,servlet意味着能够一次处理给定端点上的多个请求。如果您正在编程请求处理逻辑以显式启动一定数量的并发线程,那么您可能面临一个完全不可避免的情况,即可用线程耗尽并阻塞您的应用程序。您的任务执行程序始终配置为使用限制为有限合理大小的线程池。大多数情况下,它不大于10-20(你不需要太多线程执行你的逻辑 - 取决于任务的性质,他们竞争的资源,服务器上的处理器数量等)让我们说,您的请求处理程序(例如MVC控制器方法)调用一个或多个@Async-annotated方法(在这种情况下,Spring抽象任务执行程序并使您的操作变得简单)或明确使用任务执行程序。当您的代码执行时,它开始从池中获取可用的线程。如果您总是一次处理一个请求而没有立即的后续请求,那就没问题。 (在这种情况下,您可能正在尝试使用错误的技术来解决您的问题。)但是,如果它是一个Web应用程序,它暴露给任意(甚至已知)客户端可能正在通过请求锤击端点,您将快速耗尽线程池,请求将开始堆积,等待线程可用。仅仅因为这个原因,你应该意识到你可能走错了路 - 如果你正在考虑这样的设计。
更好的解决方案可能是 stage 要异步处理的数据(可以是队列,或任何其他类型的临时/临时数据存储)并返回响应。拥有一个外部独立应用程序,甚至是它的多个实例(部署在Web容器外部)轮询登台端点并在后台处理数据,可能使用有限数量的并发线程。这样的解决方案不仅可以为您提供异步/并发处理的优势,而且还可以扩展,因为您可以根据需要运行此类轮询器的多个实例,并且可以分配它们,指向登台端点。 HTH
答案 5 :(得分:1)
从Spring 3开始,您可以使用@Async注释:
@Service
public class smg {
...
@Async
public getCounter() {...}
}
在上下文文件中使用<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上对我很有用,你不需要管理一个线程池。