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

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

有没有推荐的方法来生成线程,使用Tomcat时的后台作业。我也使用Spring MVC进行应用程序。


答案 1

在像Tomcat或Jetty这样的准系统容器中,你最安全的赌注是使用具有最大线程量的应用宽线程,以便任务在必要时排队。ExecutorService在这方面非常有帮助。

在应用程序启动或 Servlet 初始化时,使用 Executors 类创建一个:

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

然后在 servlet 的服务期间(您可以忽略您不感兴趣的情况的结果,或者将其存储在会话中以供以后访问):

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

哪里必须实现 or 和 可以看起来像这样,其中只是你的数据,例如,用请求参数值填充(请记住,你绝对不应该传递 Servlet API 工件,如 or!):YourTaskRunnableCallableyourDataHttpServletRequestHttpServletResponse

public class YourTask implements Runnable {

    private YourData yourData;

    public YourTask(YourData yourData) {
        this.yourData = yourData;
    }

    @Override
    public void run() {
        // Do your task here based on your data.
    }
}

最后,在应用程序关闭或 servlet 销毁期间,您需要显式关闭它,否则线程可能会永远运行并阻止服务器正确关闭。

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

如果您实际上使用的是普通的JEE服务器,例如WildFly,Payara,TomEE等,其中EJB通常可用,那么您可以简单地将注释放在从servlet调用的EJB方法上。您可以选择让它返回带有具体值的 a。@AsynchronousFuture<T>AsyncResult<T>

@Asynchronous
public Future<ReturnType> submit() {
    // ... Do your job here.

    return new AsyncResult<ReturnType>(result);
}

另请参阅:


答案 2

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

CommonJ − JSR 237 Timer & WorkManager

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

为什么使用 WorkManagers?

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

安装/部署 CommonJ

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

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

2.1 容器托管线程与非托管线程

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

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

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

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

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

引用