2016-10-25 6 views
4

У меня есть ExecutorService executor = Executors.newSingleThreadExecutor();, который я хочу остановить, когда сервер выключается.ExecutorService не закрывается из contextDestroyed() при остановке Tomcat

У меня есть класс, который 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, я получаю:

SEVERE: Веб-приложение [], похоже, запустило поток с именем [pool-2-thread-1], но не смог его остановить. Вероятно, это приведет к утечке памяти.

Сразу после печати ServletContextListener destroyed.

Мне нужно снова нажать кнопку остановки, чтобы полностью остановить ее.

Почему он не отключает службу ExecutorService, хотя он достиг executor.shutdown();? Что я делаю не так?

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

Можете ли вы реализовать shutdown на этих линиях? http://stackoverflow.com/questions/36644043/how-to-forcefully-shutdown-java-executorservice/36644320#36644320 –

+0

@Ravindrababu Я скопировал его в 'contextDestroyed()', это ничего не изменило. Он не печатает '(« Пул не заканчивается »), хотя. Я также пробовал 1 секунду вместо 60. – shinzou

+0

изменение if (! Pool.awaitTermination (60, TimeUnit.SECONDS)) условие для состояния и сна в течение 60 секунд. в то время как i (! pool.awaitTermination (60, TimeUnit.SECONDS)) {Thread.sleep (1000);} –

ответ

2

Проблема в том, что у вас есть два разных экземпляра RoomsManager (и, следовательно, два разных исполнителя): сначала создается Tomcat, а второй создается вами.

Когда вы комментируете RoomsManager с помощью @WebListener, Tomcat автоматически создает экземпляр этого класса и подписывается на него, чтобы получать контекст создания/уничтожения сервлета.Этот экземпляр тот, который фактически останавливает своего исполнителя и печатает ServletContextListener destroyed.

Второй экземпляр создан вами в методе getRoomsManager (кстати, этот метод не выглядит потокобезопасным). Этот экземпляр не зарегистрирован в Tomcat и не получает событие «уничтожить» контекста сервлета, поэтому он даже не пытается отключить его исполнитель.

+0

Как я могу получить экземпляр, созданный tomcat? И ты прав, теперь я не смотрю на поток. – shinzou

+0

@kuhaku Например, 'RoomManager' может выполнять' servletContextEvent.getServletContext(). SetAttribute (..., this) 'внутри своего метода contextInitialized()', поэтому вы сможете вызвать '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()); 

Потому что, по-видимому, нить кота являются демонами, и поэтому, когда они создают новую нить с return new Thread(r, "Your name"); также становится демоном.

Но в DefaultThreadFactory, который использует служба-исполнитель, я видел, что он отключает демонс новых потоков.

Это не объясняет, почему executor.shutdown(); не работал, но теперь, по крайней мере, он правильно выключается.