簡體   English   中英

關機后Java線程仍在內存中

[英]Java thread still in memory after being shutdown

有人可以幫我解決這個問題。 下面的代碼是我用來啟動/停止某些輪詢服務的代碼。 輪詢服務使用while(boolean running)循環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 ps -ef | grep java它顯示該程序仍在后台運行。 即使投票服務已經停止了!

為什么會這樣? 我該怎么做才能解決這個問題?

您需要進行線程轉儲以查看哪些非守護程序線程仍在運行。

jstackvisualvmjconsole是一些方法。

您可以強制應用程序停止

System.exit(0);

由於輪詢是在一個守護程序線程中,它是否停止無關緊要。 該計划無論如何都會完成。

恕我直言,你不應該推出自己的boolean標志。 而是使用線程自己的中斷狀態

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

如果你讀了關於shutdownNow()的javadoc,它說

...任何無法響應中斷的任務都可能永遠不會終止

我相信如果你實現了上述邏輯,情況就不是這樣了。 此外,如果執行任何阻塞操作,則需要傳播中斷以確保線程接收到中斷。

在您的處理中,您是否正在捕獲異常並繼續處理? 你是不是允許ThreadInterruptException涓涓細流並導致線程關閉?

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

如果您看到Java進程處於活動狀態,那是因為JVM中至少有一個守護進程線程。 Thread類的API文檔說明:

Java虛擬機繼續執行線程,直到發生以下任一情況:

  • 已調用類Runtime的exit方法,並且安全管理器已允許執行退出操作。
  • 所有非守護程序線程的線程都已死亡,無論是通過從run方法調用返回還是拋出傳播超出run方法的異常。

因此, ThreadFactory實現中的這行代碼應該解釋為什么進程繼續存在:

thread.setDaemon(true);

提交給ExecutorService所有Runnable任務現在將作為守護程序線程運行。 您應該驗證已初始化的線程是否已終止。 這還包括執行輪詢循環的線程(並且不必是主線程,具體取決於您編寫Polling類的方式)。

如果您已經查看了代碼並且還沒有弄清楚哪個部分負責守護程序線程的活動,那么您將采用以下技術之一來確定阻止JVM關閉的線程:

  • SIGQUIT信號發送到Java進程。 這將為您提供JVM的線程轉儲,以及所有線程的堆棧; 如果您的JVM進程作為后台進程運行,則需要將stdout重定向到文件。 在生成的堆棧跟蹤中,您應該找到至少一個活動的守護程序線程並在應用程序中執行一段代碼。
  • 考慮為ThreadFactory發起的線程設置name 這樣,如果您使用記錄器打印出線程名稱以及run方法結束時的消息,您可以通過注意沒有任何消息來確定線程是否處於活動狀態。

您使用任何阻止隊列或任何資源? 因為它的正常工作方式是,當你調用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中提供代碼會更好

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM