2010-05-25 148 views
11

當我通過調用ScheduledExecutorService.schedule()創建線程時,它在執行計劃任務後永不終止。爲什麼由ScheduledExecutorService.schedule()啓動的線程永遠不會終止?

例如下面的程序決不會退卻:

public static void main(String[] args) { 
    ScheduledFuture scheduledFuture = 
     Executors.newSingleThreadScheduledExecutor().schedule(new Callable() { 

    public Void call() { 
     doSomething(); 
     return null; 
    } 

    }, 1, TimeUnit.SECONDS); 
} 

public static void doSomething() { 
} 

這是一個JDK錯誤,還是我只是錯過了什麼?

+0

doSomething()發生了什麼? – 2010-05-25 09:17:37

回答

2

您需要撥打scheduledExecutorService.shutdown()停止執行。否則,它會每秒重新啓動一次。

(編輯:見註釋)

+2

應該調用scheduledExecutorService。shutdown()而不是scheduleFuture.shutdown()和ScheduledExecutorService.schedule()調用是一次性操作,永遠不會再次重新啓動。 – moonese 2010-05-25 09:29:15

7

計劃的任務要麼正在執行或正在等待被執行。

如果任務正在等待執行,future.cancel()將阻止它被執行(取消(true)/取消(false))。

如果任務已被執行,future.cancel(false)將不起作用。 future.cancel(true)將中斷執行該任務的線程。 這是否會產生任何影響取決於您誰將執行該任務。根據實施情況,任務可能會或可能不會響應中斷。

爲了使您的任務響應取消,您必須實施doSomething(),以便它能響應中斷。

有做到這一點基本上有兩種方式:

1.檢查中斷標誌在你的邏輯

public void doSomething(){ 
    stuff(); 
    //Don't use Thread.interrupt() 
    if(Thread.currentThread().isInterrupted()){ 
     // We have an interruption request, possibly a cancel request 
     //Stop doing what you are doing and terminate. 
     return; 
    } 
    doLongRunningStuff(); 
} 

您必須偶爾檢查中斷標誌,如果中斷,停止你正在做什麼並返回。確保使用Thread.isInterrupted()而不是Thread.interrupt()進行檢查。在追訪例外

2.Act

public void doSomething(){ 
    try{ 
     stuff(); 
    }catch(InterruptedException e){ 
     // We have an interruption request, possibly a cancel request 

     // First, preserve Interrupted Status because InterruptedException clears the 
     // interrupted flag 
     Thread.currentThread.interrupt(); 

     // Now stop doing your task and terminate 
     return; 
    } 

    doLongRunningStuff(); 
} 

當你拋出InterruptedException的任何方法,一定要阻止你做什麼,當一個人被拋出終止。

一旦以這種方式實現您的方法,您可以調用future.cancel(true)來取消執行正在運行的任務。

+0

如何在命令被調用後關閉計劃?以釋放線程資源。畢竟,按計劃創建的任務只執行一次。 – Nickolas 2013-10-08 11:54:35

+0

@Nickolas:不確定你的意思,但是如果你的意思是一個計劃運行一次的任務(延遲等)並且它已經完成,那麼任務已經停止(並且釋放了線程)。否則我的答案仍然適用。 – 2013-10-08 12:50:32

+1

這是一個很好的答案,但對另一個問題。問題不在於如何終止任務--OP明確指出任務是一個nop - 但是如何終止用於運行任務的線程。 – oberlies 2014-04-29 16:36:04

5

您的程序永遠不會終止,因爲您創建了一個ScheduledExecutorService,該程序包含一個線程池,但您從不關閉該服務。因此,線程池中的用戶線程永遠不會終止,因此VM將永遠持續運行。

要解決此問題,您需要在執行程序服務上調用shutdown()。這甚至可以在調度您想要執行的任務後直接完成:

public static void main(String[] args) { 
    ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); 
    ScheduledFuture scheduledFuture = executorService.schedule(new Callable() { 

    public Void call() { 
     doSomething(); 
     return null; 
    } 

    }, 1, TimeUnit.SECONDS); 
    executorService.shutdown(); 
} 

這將正常執行計劃任務,然後終止池中的線程。