关机后Java线程仍在内存中

时间:2011-09-07 12:14:28

标签: java multithreading

有些人可以帮我解决这个问题。下面的代码是我用来启动/停止某些轮询服务的代码。轮询服务使用while(boolean running)循环运行。调用Polling.setRunning(false)会终止循环。

private static ExecutorService pool = Executors.newSingleThreadExecutor(new ThreadFactory() {
   @Override
   public Thread newThread(Runnable runnable) {
      Thread thread = Executors.defaultThreadFactory().newThread(runnable);
      thread.setDaemon(true);
      return thread;
   }
});

public static void start(){

    pool.submit(new Runnable() {
        public void run(){
            try{
                System.out.println("Starting Polling...");
                Polling.start();
            } catch(Exception e){
                e.printStackTrace();
            }
        }
    });

}

public static void stop(){

    System.out.println("Stopping Polling...");
    Polling.setRunning(false);
    pool.shutDownNow();
}

public static void main(String[] args) throws Exception {

    start();    //call to start

    Thread.sleep(5000);

    stop();     //call to stop

}

问题是:当我运行时,一切正常并且符合预期。但是,当我跑: ps -ef | grep java它表明该程序仍在后台运行。即使投票服务肯定已停止!

为什么会这样?我该怎么做才能解决它?

5 个答案:

答案 0 :(得分:2)

您需要进行线程转储以查看哪些非守护程序线程仍在运行。

jstackvisualvmjconsole有几种方法可以做到这一点。

您可以使用

强制停止应用程序
System.exit(0);

由于轮询是在一个守护程序线程中,它是否停止无关紧要。该计划无论如何都会完成。

答案 1 :(得分:1)

恕我直言,你不应该滚动你自己的boolean标志。而是使用线程自己的中断状态

while(!Thread.currentThread().isInterrupted()){
    // do stuff
}

如果您阅读有关shutdownNow()的javadoc,则说

  

...任何无法响应中断的任务可能永远不会终止

如果您实现了上述逻辑,我相信不会。此外,如果执行任何阻止操作,则需要传播中断以确保线程接收到中断。

答案 2 :(得分:1)

在您的处理过程中,您是否正在捕捉异常并继续处理?你是不是允许ThreadInterruptException涓涓细流并导致线程关闭?

http://download.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/ExecutorService.html#shutdownNow()

答案 3 :(得分:1)

如果您看到Java进程处于活动状态,那是因为JVM中至少有一个守护程序线程。 Thread类的API文档声明:

  

Java虚拟机继续执行线程,直到其中任何一个   发生以下情况:

     
      
  • 已调用Runtime类的退出方法和安全性   经理允许退出操作。
  •   
  • 所有非守护程序线程的线程都已死亡   从调用返回到run方法或抛出异常   传播超出run方法。
  •   

因此,ThreadFactory实现中的这行代码应该解释为什么这个过程仍然存在:

thread.setDaemon(true);

提交给Runnable的所有ExecutorService任务现在将作为守护程序线程运行。您应该验证已初始化的线程是否已终止。这还包括执行轮询循环的线程(并且不必是主线程,具体取决于您编写Polling类的方式)。

如果您已经查看了代码并且还没有弄清楚哪个部分负责守护程序线程的活动,那么您将采用以下技术之一来确定阻止JVM关闭的线程:

  • 向Java进程发送SIGQUIT信号。这将为您提供JVM的线程转储,以及所有线程的堆栈;如果您的JVM进程作为后台进程运行,则需要将stdout重定向到文件。在生成的堆栈跟踪中,您应该找到至少一个活动的守护程序线程并在您的应用程序中执行一段代码。
  • 考虑为ThreadFactory启动的主题设置name。这样,如果您使用记录器打印出线程名称以及run方法末尾的消息,您可以通过注明没有任何消息来确定线程是否存活。

答案 4 :(得分:1)

您使用的是阻塞队列还是任何资源?因为它正常工作的原因是,当你调用shutDownNow()时,它会向线程抛出一个中断,如果池线程没有开始执行Runnable,它会终止,如果没有则它必须等到结束。 现在重点是,如果你使用带有Selector的BlockingQueue或Asynchronous I / O,或者其他什么,每个都有自己的处理中断的策略。假设您使用了BlockingQueue,并说它正在等待Runnable,并且在收到中断的同时,它会抛出InterruptedException并清除中断状态。 即你将手动让堆栈知道,中断被抛出:

try{
runnable.run();
}
catch(InterruptedException ex)
{
Thread.currentThread.interrupt();//let the stack know that interrupt was thrown.
}

如果您的情况是上述情况,如果没有catch语句,则线程永远不会终止,因为一旦抛出Exception,就会清除中断状态。 因此,根据您使用的包,请检查中断策略。 如果你能在Polling中提供代码

会更好