2012-03-28 27 views
1

我需要創建異步線程,運行一次,延遲時間爲2分鐘,可以在任何時刻終止。我看見幾個可能的解決方案:定時器:取消正在運行的任務

  1. ScheduledExecutorServiceFutureTask讓我中斷正在運行的任務,但我將不得不調用shutdown()終止所有正在運行的線程,這將阻止用戶直到進程被終止。此外,我將不得不經常調用Thread.interrupted(),如Enno Shioji's answer中所述。
  2. TimerTimerTask不需要釋放運行的線程,但我沒有辦法打斷一個正在運行的計時器線程(Timer.cancel()剛剛取消的未來計劃)
  3. 使用Thread and sleepthread interruption問題。

有沒有很好的解決方案? (我使用Tomcat 7)

謝謝

回答

1

一些試驗和研究後,FutureTask.cancel()和線程需要中斷的類似處理,如Enno Shioji's answer

  1. 檢查中斷標誌在你的邏輯
  2. 法追訪時表示例外

例子tes TS中斷標誌:

private final class MyTask implements Runnable { 

    public void run() { 
     try{ 
      for(int j=0; j<100000000; j++) { 
       for(int i=1; i<1000000000; i++){ 
        if(Thread.interrupted()){ //Don't use Thread.interrupt()! 
         Log.debug("Thread was interrupted for" + cache); 
         return; //Stop doing what you are doing and terminate. 
        } 
        Math.asin(0.1565365897770/i); 
        Math.tan(0.4567894289/i); 
       } 
      }        
     }catch(Throwable e){//if exception is uncaught, the scheduler may not run again 
      ... 
     } 
    } 
} 

據我瞭解,ScheduledExecutorService也許是shutdown當應用程序結束運行

0

使用選項1,您可以使用FutureTask.cancel()mayInterruptIfRunning參數設置爲true取消任務。

ScheduledExecutorService.scheduleAtFixedRate()創建一個ScheduledFuture,仍然可以通過FutureTask api取消。

這是我用來驗證任務被取消的天真測試。如果你做了一些阻塞IO(網絡或磁盤),我想工作者線程可能不會被打斷,但我還沒有測試過。如果在任務沒有運行的時候調用cancel函數,這一切都會很好地停止,但是如果在調用cancel函數時任務正在運行,執行程序將嘗試終止線程。

public static void main(String[] args) throws InterruptedException { 
    ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(2); 

    ScheduledFuture<?> future = executor.scheduleAtFixedRate(new Runnable() { 
     int i = 0; 
     public void run() { 
      int j = i++; 
      System.err.println("Run " + j); 

      try { 
       Thread.sleep(5000L); 
      } catch (InterruptedException e) { 
       System.err.println("Interrupted " + j); 
      } 
     } 

    }, 1000L, 2000L, TimeUnit.MILLISECONDS); 

    Thread.sleep(10000L); 
    System.err.println("Canceled " + future.cancel(true)); 

    Thread.sleep(20000L); 

    executor.shutdownNow(); 
    System.err.println("Finished"); 
} 
+0

沒錯,但有兩個缺點。首先,如果我在線程中啓動一個長進程,我必須不斷地引用isInterrupted標誌;第二,我必須調用shutdown來釋放正在運行的線程,這將阻塞用戶,直到線程運行完畢 – lili 2012-03-28 19:27:09

+0

ExecutorService返回的FutureTask將您抽象爲使用線程。按照JavaDoc,如果您爲mayInterruptIfRunning傳遞true,它將負責中斷工作線程。 – 2012-03-28 19:34:45

+0

不完全是根據恩諾鹽路的回答是:http://stackoverflow.com/questions/2903342/why-thread-started-by-scheduledexecutorservice-schedule-never-quits – lili 2012-03-28 19:36:09

1

您的方案2的TimerTask,爲什麼不從run()方法返回調用this.cancel後( )?

這是我寫的東西的片段。每當工具遇到會導致進一步執行無效的情況時(例如錯誤配置),我都會使用相同的技術。

... 
if (count < 1) { 
    logger.error("CANCELING THREAD FOR " + host + ":" + jmxPort + "! " + 
       "- CONFIGURATION INCOMPLETE - DUMP_COUNT must be 1 or greater."); 
    this.cancel(); 
    return; 
} 
...