我在Apache Tomcat 6上运行多线程Java Web应用程序。而不是使用new Thread();
反模式,我将线程实例化留给Tomcat(参见下面的代码)。
我在最后几天注意到Web应用程序越来越慢。重新启动servlet容器后,一切都恢复正常。
由于我在处理它们之后没有终止线程(不知道我是否必须或者垃圾收集器是否会破坏它们),我猜这是造成性能损失的原因。
代码基本上如下所示:
自定义服务器侦听器(我将此添加到web.xml):
public class MyTaskRunner implements ServletContextListener {
public static final ExecutorService EXECUTOR_SERVICE = ExecutorService.newFixedThreadPool(10000);
public void contextDestroyed(ServletContextEvent sce) {
EXECUTOR_SERVICE.shutdownNow();
}
public void contextInitialized(ServletContextEvent sce) {
}
}
线程实例化:
for (Object foo : bar){
MyTaskRunner.EXECUTOR_SERVICE.submit(new Runnable() {
public void run() {
doSomethingWith(foo);
});
}
那么,run()
完成后我有什么特别的事吗?
答案 0 :(得分:3)
您是否正确地在web.xml中注册了上下文侦听器?
你的跑步方法在某个时候结束了吗?还是他们一直无限期地运行?
ExecutorSerfice将简单地为你调用Thread.start,你仍然在你的webapp中启动线程,只要你正确地关闭它们,这本身并不是一件可怕的事情。无论你使用什么tecnique,run()方法的执行都不会被截断。
答案 1 :(得分:3)
关于线程和GC的一些基本事实:
当一个线程正在运行时,它不会被垃圾回收。
当线程终止时,其堆栈将被删除,并且Thread
对象将从ThreadGroup
数据结构中删除。线程状态的其余部分遵循正常的可达性规则。
您不需要做任何特殊的事情来使线程终止。它发生在run
方法调用结束时,无论是因为它返回,还是因为它以(未捕获的)异常退出。
现在针对您的特定问题。很多事情都可能导致性能下降。例如:
你的一些主题可能会卡住;例如等待锁定,等待无法到达的通知,或者只是陷入无限的CPU循环。
您可能运行了太多线程(执行有用或半有用的操作),并且减速可能是锁争用,CPU资源不足或颠簸的结果。
您可能有某种内存泄漏,并且减速可能是您的应用程序开始耗尽堆空间的一种症状。
要弄清楚发生了什么,您需要进行一些性能监控:
查看操作系统级别统计信息以查看应用程序是否正在颠簸。
使用内存配置文件查看应用程序是否内存不足。如果是,请查看是否存在内存泄漏,并将其跟踪。
使用性能分析器查看是否存在特定热点,或者是否存在大量锁定争用。
我同意这个评论。线程池大小为10000 危险大。它应该是一个小常量乘以应用程序可用的核心数。
答案 2 :(得分:1)
new Thread();反模式
你们在哪里得到这是一种反模式?
无论如何,10000线程太多了。每个线程占用内存,操作系统有自己的局限性,因此,作为安全路径,尽量不要超过几千个线程。
连接jconsole(jstack可能就足够了)看看你的线程在做什么 - 无论是睡觉还是等待什么。
并且不是Tomcat管理线程,它是java中的ExecutorService。