【发布时间】:2015-01-27 12:37:28
【问题描述】:
我正在阅读 Async servlets 3.1
据说当有很多耗时的操作要完成时,发送请求的线程会被释放,例如从数据库中获取一长串数据。
我无法理解这里的好处,因为无论如何都会分配一个新线程来处理数据库连接和响应处理,即使负责请求的初始线程已被释放。
那么,Async servlet 如何比我们之前使用的每个请求线程模型更有益。
【问题讨论】:
我正在阅读 Async servlets 3.1
据说当有很多耗时的操作要完成时,发送请求的线程会被释放,例如从数据库中获取一长串数据。
我无法理解这里的好处,因为无论如何都会分配一个新线程来处理数据库连接和响应处理,即使负责请求的初始线程已被释放。
那么,Async servlet 如何比我们之前使用的每个请求线程模型更有益。
【问题讨论】:
只有这么多线程可用于服务 HTTP 请求。这些来自 HTTP 线程池,可通过您的应用程序服务器配置机制(例如 Glassfish 的管理 UI)进行配置。如果您的 servlet 执行长时间运行的操作,这些请求线程将被占用。一旦所有池化的请求线程都被占用,在一个被释放之前,将无法处理更多的请求。
使用异步 servlet,请求线程将返回到池中,而不是在非异步情况下被长时间运行的同步操作阻塞。
【讨论】:
But isnt the Async operation like for e.g. Data Retrieval from DB going to consume a new thread - 是的,这是一个真正的风险。如果您不小心,您只会将一个线程换成另一个线程。如果 HTTP 线程和异步处理线程都来自一个池(通常是这种情况),那么您可以很好地为 HTTP 池分配更多线程,因为最终效果将毫无意义。
这里分两部分回答:
更新:如果我们已经在使用 NIO 线程池,为什么需要 Async Servlets 的更多细节 不久前,我确实在http://manish-m.com/?p=996 上记下了关于非阻塞 IO 的笔记。您还可以在http://manish-m.com/?p=915 上查看相关帖子(尤其是此页面上的 IO Playground 部分)。
NIO 线程池用于处理多个连接请求。它利用内核的非阻塞 IO 特性,使得少量线程可以处理多个连接。
但是,从网络缓冲区读取数据的线程也会执行“用户代码”(我们在 servlet 中编写的代码)。 NIO 的 servlet 容器框架处理接受客户端请求,但它不能自己处理由我们编写的“阻塞用户代码”。因此,如果我们编写一个需要 10 秒的 DB 查询,那么容器框架无法自行异步处理它。我们将通过在 servlet 中编写任何阻塞代码来阻塞原始 NIO 线程池。因此,我们需要显式编写任何我们认为可能会阻塞容器的请求线程的内容,作为 Java EE 中的异步 servlet。
同样,当我们使用 Netty、MINA 等其他 NIO 框架时,我们需要注意确保代码“不会”阻塞处理网络连接的 NIO 线程。这通常通过将如此长时间运行的任务卸载到另一个线程池来实现(这是容器在您编写异步 servlet 时所做的事情)。
【讨论】: