【问题标题】:Why UserThread running with ScheduleExecutorService does not get garbage collected为什么使用与 ScheduledExecutorService 一起运行的线程不会被垃圾收集
【发布时间】:2012-05-17 15:57:55
【问题描述】:

请帮我在下面的代码中找到线程泄漏的原因。 TestThread 即使在 run() 完成(通过控制台打印语句验证)并且主方法已退出(通过 print 语句和分析器工具验证)后也不会被垃圾收集。

但是,如果TestThread 设置为守护线程,即t.setDaemon(true),则会被垃圾回收。下面的代码只是一个示例代码,它说明了我的应用程序中的问题。我正在尝试使用一些预先存在的调度类(它是由其他人使用ScheduledExecutorService 设计的)。我注意到,当我继续为该类调度多个 Runnables 时,创建的线程永远不会被垃圾回收。

public class ThreadTest {

  static void runThreadWithExecutor() {
    final String name = "TestThread";
    ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor(
        new ThreadFactory() {
          @Override
          public Thread newThread(Runnable r) {
            Thread t = new Thread(r, name);
            t.setDaemon(false);
            return t;
          }
        });

    ses.schedule(new Runnable() {
        @Override
        public void run() {
           System.out.println("entered " + name);
           System.out.println("exiting " + name);
        }},
      2,
      TimeUnit.SECONDS);
    }

  public static void main(String[] args) throws InterruptedException {
    System.out.println("entered main");
    runThreadWithExecutor();
    Thread.sleep(5000);
    System.out.println("exiting main");
  }
}

【问题讨论】:

    标签: java multithreading executorservice


    【解决方案1】:

    这是因为您在安排上一份工作后没有在执行程序服务上调用 shutdown()

    ses.schedule(...);
    // this stops any management threads but existing jobs will still run
    ses.shutdown();
    

    我刚刚将shutdown() 调用添加到您的代码中,它可以正常退出。所有ExecutorServices 都是如此。在没有关闭的情况下,线程池将继续等待提交更多作业,并且永远不会被 GC。

    有关更多详细信息,请参阅下面@John 的回答。

    【讨论】:

      【解决方案2】:

      @Gray 的评估是正确的,我只是想我补充一下为什么他是正确的。 ExecutorService 是一个线程池,它将重用线程。

      new Thread(runnable).start(); 不同,当run 方法完成时,线程完成,然后将被GC'd。当 Executor Runnable 完成时,线程将坐在那里等待另一个可运行的任务被提交和使用。因此,通过关闭,您是在告诉执行程序结束线程池中的所有线程。

      回答你的最后一部分。将其设置为守护程序仅是因为没有其他(非守护程序)线程在运行。如果您的应用程序启动了其他一些非守护线程,则 Executor 线程将继续。请记住,只有守护线程在运行时,守护线程将被终止。

      【讨论】:

      • 好信息约翰。一个微调。 shutdown() 在所有作业都已经提交完成之前不会结束线程池中的所有线程。
      • 谢谢大家。虽然我最初选择了这个作为我接受的答案,但后来我选择了 Gray's,因为没有 Gray's 这个答案是不言自明的。然而,这个回复给了我自信地修改代码所需的完整解释:)它有效!
      猜你喜欢
      • 2011-12-05
      • 2010-12-19
      • 2014-08-08
      • 1970-01-01
      • 1970-01-01
      • 2020-06-14
      • 1970-01-01
      • 1970-01-01
      • 2013-04-25
      相关资源
      最近更新 更多