2017-06-16 210 views
1

我有一個Web應用程序(使用Spring /春天啓動)在Tomcat 7.There運行被等被定義一些的ExecutorService:當tomcat關閉時,ExecutorService管理的線程會發生什麼情況?

public static final ExecutorService TEST_SERVICE = new ThreadPoolExecutor(10, 100, 60L, 
     TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(1000), new ThreadPoolExecutor.CallerRunsPolicy()); 

的任務很重要,必須正確完成。我捕捉到的異常以及它們保存到數據庫的重試,就像這樣:

try { 
     ThreadPoolHolder.TEST_SERVICE.submit(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        boolean isSuccess = false; 
        int tryCount = 0; 
        while (++tryCount < CAS_COUNT_LIMIT) { 
         isSuccess = doWork(param); 
         if (isSuccess) { 
          break; 
         } 
         Thread.sleep(1000); 
        } 
        if (!isSuccess) { 
         saveFail(param); 
        } 
       } catch (Exception e) { 
        log.error("test error! param : {}", param, e); 
        saveFail(param); 
       } 
      } 
     }); 
    } catch (Exception e) { 
     log.error("test error! param:{}", param, e); 
     saveFail(param); 
    } 

所以,當Tomcat關閉,將發生在池的線程是什麼(正在運行或在隊列中等待)?如何確保所有任務或者在關機前正確完成,或者保存到數據庫重試?

回答

1

Tomcat內置了線程泄漏檢測功能,所以在應用程序解除部署時應該會出現錯誤。作爲開發人員是你的責任鏈接創建的Web應用程序生命週期的任何對象,這意味着你永遠也不會有如果您在使用Spring引導未常數

靜止狀態時,你的Spring上下文已經鏈接到應用程序生命週期,所以最好的方法是將你的執行器創建爲Spring bean,並讓Spring在應用程序停止時關閉它。這裏是你可以放入任何@Configuration類的例子。

@Bean(destroyMethod = "shutdownNow", name = "MyExecutorService") 
public ThreadPoolExecutor executor() { 
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 100, 60L, 
      TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(1000), 
      new ThreadPoolExecutor.CallerRunsPolicy()); 
    return threadPoolExecutor; 
} 

正如您所看到的,@Bean註釋允許您指定在Spring上下文關閉時執行的destroy方法。另外我添加了name屬性,這是因爲Spring通常會爲異步Web處理等東西創建一些ExecutorServices。當您需要使用執行程序時,只需將Autowire與其他任何spring bean一起使用即可。

@Autowired 
@Qualifier(value = "MyExecutorService") 
ThreadPoolExecutor executor; 

記住靜態是EVIL,你應該只對常量和可能不可變的obbjects使用靜態。

編輯

如果需要,直到任務已經處理,以阻止雄貓關機程序,你需要用一個組件執行人進行更多的控制,像這樣。

@Component 
public class ExecutorWrapper implements DisposableBean { 

    private final ThreadPoolExecutor threadPoolExecutor; 

    public ExecutorWrapper() { 
     threadPoolExecutor = new ThreadPoolExecutor(10, 100, 60L, 
       TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(1000), new ThreadPoolExecutor.CallerRunsPolicy()); 
    } 

    public <T> Future<T> submit(Callable<T> task) { 
     return threadPoolExecutor.submit(task); 
    } 

    public void submit(Runnable runnable) { 
     threadPoolExecutor.submit(runnable); 
    } 

    @Override 
    public void destroy() throws Exception { 
     threadPoolExecutor.shutdown(); 
     boolean terminated = threadPoolExecutor.awaitTermination(1, TimeUnit.MINUTES); 
     if (!terminated) { 
      List<Runnable> runnables = threadPoolExecutor.shutdownNow(); 
      // log the runnables that were not executed 
     } 
    } 
} 

有了這個代碼,你叫shutdown第一所以沒有新的任務可提交,然後等待一些時間執行完成當前任務和隊列。如果未及時完成,請致電shutdownNow中斷正在運行的任務,並獲取未處理的任務列表。

注意: DisposableBean有竅門,但最好的解決方案實際上是實現SmartLifecycle接口。你必須實現更多的方法,但是你可以得到更多的控制,因爲直到所有的bean都被實例化並且整個bean層次結合在一起之前,線程纔會被啓動,它甚至允許你指定應該在哪些命令中啓動組件。

+0

謝謝!它真的更優雅。但是當tomcat關閉時會發生什麼?我擔心未完成的任務正在運行或在隊列中。如何確保在tomcat重啓時完成所有任務。 – sxzhou

+0

我將編輯包含該場景的答案 –

1

作爲任何Java應用程序的Tomcat將不會結束,直到所有非daeon線程都將結束。上例中的ThreadPoolExecutor使用默認線程工廠,並將創建非守護線程。

相關問題