如何在Java中终止容器创建的线程

时间:2011-08-09 00:31:26

标签: java multithreading

我在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()完成后我有什么特别的事吗?

3 个答案:

答案 0 :(得分:3)

您是否正确地在web.xml中注册了上下文侦听器?

你的跑步方法在某个时候结束了吗?还是他们一直无限期地运行?

ExecutorSerfice将简单地为你调用Thread.start,你仍然在你的webapp中启动线程,只要你正确地关闭它们,这本身并不是一件可怕的事情。无论你使用什么tecn​​ique,run()方法的执行都不会被截断。

答案 1 :(得分:3)

关于线程和GC的一些基本事实:

  • 当一个线程正在运行时,它不会被垃圾回收。

  • 当线程终止时,其堆栈将被删除,并且Thread对象将从ThreadGroup数据结构中删除。线程状态的其余部分遵循正常的可达性规则。

  • 您不需要做任何特殊的事情来使线程终止。它发生在run方法调用结束时,无论是因为它返回,还是因为它以(未捕获的)异常退出。


现在针对您的特定问题。很多事情都可能导致性能下降。例如:

  • 你的一些主题可能会卡住;例如等待锁定,等待无法到达的通知,或者只是陷入无限的CPU循环。

  • 您可能运行了太多线程(执行有用或半有用的操作),并且减速可能是锁争用,CPU资源不足或颠簸的结果。

  • 您可能有某种内存泄漏,并且减速可能是您的应用程序开始耗尽堆空间的一种症状。

要弄清楚发生了什么,您需要进行一些性能监控:

  • 查看操作系统级别统计信息以查看应用程序是否正在颠簸。

  • 使用内存配置文件查看应用程序是否内存不足。如果是,请查看是否存在内存泄漏,并将其跟踪。

  • 使用性能分析器查看是否存在特定热点,或者是否存在大量锁定争用。


我同意这个评论。线程池大小为10000 危险大。它应该是一个小常量乘以应用程序可用的核心数。

答案 2 :(得分:1)

  

new Thread();反模式

你们在哪里得到这是一种反模式?

无论如何,10000线程太多了。每个线程占用内存,操作系统有自己的局限性,因此,作为安全路径,尽量不要超过几千个线程。

连接jconsole(jstack可能就足够了)看看你的线程在做什么 - 无论是睡觉还是等待什么。

并且不是Tomcat管理线程,它是java中的ExecutorService。