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.

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

TA贡献1998条经验 获得超6个赞
我知道这是一个老问题,但人们一直在问它,试图做这种事情(在处理servlet请求时显式产生线程)一直......这是一个非常有缺陷的方法 - 出于多个原因。 ..简单地说Java EE容器对这种做法不满意是不够的,尽管一般都是......
最重要的是,人们永远无法预测servlet在任何给定时间将接收多少并发请求。根据定义,Web应用程序,servlet意味着能够一次处理给定端点上的多个请求。如果您正在编程请求处理逻辑以显式启动一定数量的并发线程,那么您可能面临一个完全不可避免的情况,即可用线程耗尽并阻塞您的应用程序。您的任务执行程序始终配置为使用限制为有限合理大小的线程池。大多数情况下,它不大于10-20(你不需要太多线程执行你的逻辑 - 取决于任务的性质,他们竞争的资源,服务器上的处理器数量等)让我们说,你的请求处理程序(例如 MVC控制器方法)调用一个或多个@Async-annotated方法(在这种情况下,Spring抽象任务执行程序并使事情变得简单)或明确使用任务执行程序。当您的代码执行时,它开始从池中获取可用的线程。如果您总是一次处理一个请求而没有立即的后续请求,那就没问题。(在这种情况下,您可能正在尝试使用错误的技术来解决您的问题。)但是,如果它是一个Web应用程序,它暴露给任意(甚至已知)客户端可能正在通过请求锤击端点,您将快速耗尽线程池,请求将开始堆积,等待线程可用。仅仅因为这个原因,你应该意识到你可能走错了路 - 如果你正在考虑这样的设计。当您的代码执行时,它开始从池中获取可用的线程。如果您总是一次处理一个请求而没有立即的后续请求,那就没问题。(在这种情况下,您可能正在尝试使用错误的技术来解决您的问题。)但是,如果它是一个Web应用程序,它暴露给任意(甚至已知)客户端可能正在通过请求锤击端点,您将快速耗尽线程池,请求将开始堆积,等待线程可用。仅仅因为这个原因,你应该意识到你可能走错了路 - 如果你正在考虑这样的设计。当您的代码执行时,它开始从池中获取可用的线程。如果您总是一次处理一个请求而没有立即的后续请求,那就没问题。(在这种情况下,您可能正在尝试使用错误的技术来解决您的问题。)但是,如果它是一个Web应用程序,它暴露给任意(甚至已知)客户端可能正在通过请求锤击端点,您将快速耗尽线程池,请求将开始堆积,等待线程可用。仅仅因为这个原因,你应该意识到你可能走错了路 - 如果你正在考虑这样的设计。)但是,如果它是一个Web应用程序,它暴露给任意(甚至已知)客户端可能正在通过请求锤击端点,您将很快耗尽线程池,并且请求将开始堆积,等待线程成为可用。仅仅因为这个原因,你应该意识到你可能走错了路 - 如果你正在考虑这样的设计。)但是,如果它是一个Web应用程序,它暴露给任意(甚至已知)客户端可能正在通过请求锤击端点,您将很快耗尽线程池,并且请求将开始堆积,等待线程成为可用。仅仅因为这个原因,你应该意识到你可能走错了路 - 如果你正在考虑这样的设计。
一个更好的解决方案可以是阶段性的数据要被处理异步(这可能是一个队列,或任何其它类型的临时/分段数据存储器),并返回该响应。拥有一个外部独立应用程序,甚至是它的多个实例(部署在Web容器外部)轮询登台端点并在后台处理数据,可能使用有限数量的并发线程。这样的解决方案不仅可以为您提供异步/并发处理的优势,而且还可以扩展,因为您可以根据需要运行此类轮询器的多个实例,并且可以分配它们,指向登台端点。HTH
添加回答
举报