Java、Tomcat、ServletContextListener 和后台线程
我有一个处理特定传入请求的 servlet。我们将其称为“UpdateUserStats”。我希望呼叫速度快,但我也需要请求来执行一项相当昂贵的任务。我认为,如果让 UpdateUserStats servlet 完成决定成功或失败的所有工作,保留新状态,然后将一些工作排入后台线程来处理并立即返回成功,这可能是一个很好的解决方案。
这看起来不错,但我想知道如何处理关闭。当服务器关闭时,我想确保它不会杀死后台线程,直到没有更多的工作剩余。我正在考虑使用 tomcat ServletContextListener 让后台线程知道服务器正在关闭,一旦队列结束就可以退出,但我不能 100% 确定这将如何表现。仅在所有请求处理完毕后才会使用 contextDestroyed()
吗?界面似乎暗示了这一点,但我在文档中没有找到它。另外,我想知道 Tomcat 在因为后台线程没有终止而生气之前愿意等待多长时间。
或者,有更好的方法来处理这个问题吗?如果 Spring 具有一些神奇的请求后后台工作功能,那么它就是一个 Spring 应用程序。
I have a servlet that handles a particular incoming request. We'll call it `UpdateUserStats'. I want the call to be fast, but I also need the request to do a reasonably expensive task. I thought that it might be a nice solution if I let the UpdateUserStats servlet do all of the work that determines success or failure, persist the new state, and then enqueue some work for a background thread to take care of and return success immediately.
This seems nice, but I'm wondering how to handle shutdown. When the server shuts down, I want to make sure that it doesn't kill the background thread until no more work remains. I was thinking of using a tomcat ServletContextListener to let the background thread know that the server is going down and it is alright to quit out once the queue ends, but I'm not 100% sure of how this will behave. Will contextDestroyed()
only after all requests are done processing? The interface seems to imply this, but I didn't find it in the documentation. Also, I wonder how long Tomcat is willing to wait around before getting angry that a background thread isn't terminating.
Alternately, is there a better way to handle this problem? It's a Spring app if perhaps Spring has some magic post-request background work functionality.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
根据 servlet 规范文档
“在应用程序关闭时,监听器会按照与其声明相反的顺序收到通知
向会话侦听器发出的通知先于向上下文侦听器发出的通知。
会话侦听器必须在上下文侦听器之前收到会话失效通知
被通知应用程序关闭。”
所以这应该是第一个处理通知线程完成其工作的侦听器。
我使用过 tomcat,据我所知,它不会等待超过 10-15 秒就放弃如果侦听器此时尚未完成,则执行干净关闭。
通常,所有容器(例如 Spring)都会在关闭期间使用侦听器进行干净退出。
Based on servlet spec documentation
"On application shutdown, listeners are notified in reverse order to their declarations
with notifications to session listeners preceeding notifications to context listeners.
Session listeners must be notified of session invalidations prior to context listeners
being notified of application shutdown."
So this should be the first listener which handles notifying the thread to complete its job.
I have used tomcat and as far a I have seen, it would not wait for more than 10-15 seconds before giving up doing a clean shutdown if the listener does not finish by then.
Typically all containers like Spring use listener for a clean exit during shutdown
提到替代方案,您可以在单独的 JVM 中创建队列(使用 ActiveMQ、RabbitMQ 或更简单的东西)。这样,即使 tomcat 宕机,任务一旦入队也会被处理。
Mentioning about alternative, you can create the queue in separate JVM (use ActiveMQ, RabbitMQ or something even simpler). That way, task once enqueued will be processed even if tomcat goes down.
您可以在应用程序范围内使用最大线程数的 ThreadPool,然后它将在必要时排队并能够根据硬件和线程任务进行配置。为此,您需要使用 ExecutorService : http:// /download.oracle.com/javase/6/docs/api/java/util/concurrent/ExecutorService.html
ThreadPool 可以初始化如下
executorPool = Executors.newFixedThreadPool(50);
在您的服务方法中,您可以定义提交到线程,如下所示:
executorPool.submit(new ProcessTask());
在销毁/关闭期间可以按如下方式清理线程池(应用程序)
executorPool.shutdownNow();
希望这有帮助
You can use ThreadPool with max no of threads application wide, then it will queued whenever necessary and able to configure based on hardware and thread task. For that you need to use ExecutorService : http://download.oracle.com/javase/6/docs/api/java/util/concurrent/ExecutorService.html
ThreadPool can initialize as below
executorPool = Executors.newFixedThreadPool(50);
In your service method, you can define submit to thread as below:
executorPool.submit(new ProcessTask());
Cleanup ThreadPool can be done as below during destroy/shutdown (application)
executorPool.shutdownNow();
Hope this helpful