2016-10-25 91 views
4

我有一個ExecutorService executor = Executors.newSingleThreadExecutor();,我想在服務器關閉時停止。當停止Tomcat時,ExecutorService不會從contextDestroyed()中關閉

我有一個類,implements ServletContextListener,它的註釋與@WebListener

我有這個類的兩個方法:

@Override 
public void contextInitialized(ServletContextEvent servletContextEvent) { 
    System.out.println("ServletContextListener started"); 
} 

@Override 
public void contextDestroyed(ServletContextEvent servletContextEvent) { 
    executor.shutdown(); 
    executor.shutdownNow(); 
    System.out.println("ServletContextListener destroyed"); 
} 

而且我看到它打印出什麼是在他們兩人的時候它應該,但是當我再按下intelij停止按鈕,我得到:

嚴重:Web應用程序[]似乎已啓動名爲[pool-2-thread-1]的線程,但未能停止它。這很可能造成內存泄漏。

緊隨其後印刷ServletContextListener destroyed

我需要再次按下停止按鈕以完全停止它。

爲什麼即使達到了executor.shutdown();也沒有關閉ExecutorService?我究竟做錯了什麼? PS:這是我唯一的ExecutorService,沒有其他線程是由我製作的。

EDIT2:

執行人服務是在一個單獨的類的字段,它與類初始化:

private ExecutorService executor = Executors.newSingleThreadExecutor(); 

這是類如何初始化(延遲初始化):

public static RoomsManager getRoomsManager(ServletContext servletContext) { 
    if (servletContext.getAttribute(MANAGER_GAMES_ATTRIBUTE_NAME) == null) { 
     servletContext.setAttribute(MANAGER_GAMES_ATTRIBUTE_NAME, new RoomsManager()); 
    } 
    return (RoomsManager)servletContext.getAttribute(MANAGER_GAMES_ATTRIBUTE_NAME); 
} 

並註明如下:

@WebListener 
public class RoomsManager implements ServletContextListener { 

停止按鈕是intelij IDEA中播放和調試按鈕附近的紅色正方形。

+0

你可以在這些行上實現關閉嗎? http://stackoverflow.com/questions/36644043/how-to-forcefully-shutdown-java-executorservice/36644320#36644320 –

+0

@Ravindrababu我把它複製到'contextDestroyed()',它沒有改變任何東西。它不打印'(「池沒有終止」);'雖然。我也嘗試了1秒而不是60. – shinzou

+0

如果(!pool.awaitTermination(60,TimeUnit.SECONDS))條件改變,而條件和睡眠時間爲60秒。而我(!pool.awaitTermination(60,TimeUnit.SECONDS)){Thread.sleep(1000);} –

回答

2

問題是你有兩個不同的RoomsManager實例(因此有兩個不同的executors):第一個是由Tomcat創建的,第二個是由你創建的。

當您註釋RoomsManager@WebListener時,Tomcat會自動創建該類的實例並訂閱它以接收servlet上下文創建/銷燬事件。該實例是實際停止其執行程序並打印ServletContextListener destroyed的實例。

第二個實例由您在getRoomsManager方法中創建(順便說一句,該方法看起來不是線程安全的)。這個實例沒有在Tomcat中註冊,也沒有收到servlet上下文的「銷燬」事件,所以它甚至不會嘗試關閉其執行程序。

+0

如何獲取tomcat創建的實例?而且你是對的,現在看來它不是線程安全的。 – shinzou

+0

@kuhaku例如,'RoomsManager'可以在'contextInitialized()'方法內執行'servletContextEvent.getServletContext()。setAttribute(...,this)',所以你可以調用'getAttribute(...)。 )'得到它。 – Roman

+0

謝謝,做到了。他們真的應該改進他們的文檔,我沒有看到任何地方提到tomcat自己創建一個實例。 https://tomcat.apache.org/tomcat-7.0-doc/servletapi/javax/servlet/annotation/WebListener.html – shinzou

1

這樣做的工作:

class YourThreadFactory implements ThreadFactory { 
    public Thread newThread(Runnable r) { 
     return new Thread(r, "Your name"); 
    } 
} 
private ExecutorService executor = Executors.newSingleThreadExecutor(new YourThreadFactory()); 

因爲很顯然,tomcat的的線程是守護進程,因此,當他們創建一個新線程return new Thread(r, "Your name");它也成爲一個守護進程。

但是在執行程序服務使用的DefaultThreadFactory中,我看到它確保新線程的守護進程關閉。

這並不能解釋爲什麼executor.shutdown();雖然沒有工作,但現在至少它正常關閉。

相關問題