Вызов System.exit () в методе destroy () сервлета - PullRequest
5 голосов
/ 13 февраля 2009

Это продолжение моего предыдущего вопроса .

В Tomcat 5.0.28 была ошибка, из-за которой контейнер destroy () не вызывал метод сервлета при завершении работы. Это исправлено в Tomcat 5.0.30, но если бы метод destroy () сервлета имел System.exit (), это привело бы к тому, что служба windows Tomcat выдавала ошибку 1053 и отказывалась корректно завершить работу (см. Ссылку выше для получения дополнительной информации о эта ошибка)

Кто-нибудь знает, является ли:

  • Хорошей идеей является вызов System.exit () внутри метода destroy () сервлета для принудительного уничтожения любых потоков, не являющихся демонами?

  • Почему Tomcat 5.0.30 и (в более поздних версиях, включая Tomcat 6.x.x) не удается правильно завершить работу, если в методе destroy () сервлета есть метод System.exit ().

Ответы [ 4 ]

16 голосов
/ 13 февраля 2009

Вызов System.exit () внутри метода destroy () сервлета для принудительного уничтожения любых потоков, не являющихся демонами, является хорошей идеей?

Это абсолютно не хорошая идея - это ужасная идея. Метод destroy() вызывается, когда сервлет выводится из эксплуатации, что может происходить по ряду причин: сервлет / веб-приложение остановлено, веб-приложение отменено, веб-приложение перезапускается и т. Д.

System.exit() закрывает всю JVM ! Почему вы хотите принудительно завершить работу всего сервера просто потому, что один сервлет выгружается?

Почему Tomcat 5.0.30 и (в более поздних версиях, включая Tomcat 6.x.x) не удается правильно завершить работу, если в методе destroy () сервлета есть метод System.exit ().

Вероятно, чтобы предотвратить такое опасное поведение, как это.

Вы не должны писать код, который предполагает, что ваш код / ​​приложение - единственное, что работает на сервере.

12 голосов
/ 13 февраля 2009

Вы задаете два вопроса:

Вопрос 1. Является ли хорошей идеей вызывать System.exit () внутри метода destroy () сервлета для принудительного уничтожения потоков, не являющихся демонами?

Вызов System.exit () внутри ЛЮБОГО метода, связанного с сервлетом, всегда неверен на 100%. Ваш код - не единственный код, работающий в JVM - , даже если вы являетесь единственным сервлетом, выполняющим (в контейнере сервлета есть ресурсы, которые необходимо будет очистить, когда JVM действительно выйдет.)

Правильный способ обработки этого случая - очистить ваши потоки в методе destroy (). Это означает запуск их таким образом, который позволяет вам аккуратно остановить их правильным способом. Вот пример (где MyThread является одним из ваших потоков и расширяет ServletManagedThread):

 public class MyServlet extends HttpServlet {
    private List<ServletManagedThread> threads = new ArrayList<ServletManagedThread>();     

     // lots of irrelevant stuff left out for brevity

    public void init() {
        ServletManagedThread t = new MyThread();
        threads.add(t);
        t.start();
    }

    public void destroy() {
        for(ServletManagedThread thread : threads) {
           thread.stopExecuting();
        }
    }
 }

 public abstract class ServletManagedThread extends Thread {

    private boolean keepGoing = true;

    protected abstract void doSomeStuff();
    protected abstract void probablySleepForABit();
    protected abstract void cleanup();

    public void stopExecuting() {
       keepRunning = false;
    }

    public void run() {
       while(keepGoing) {
            doSomeStuff();
            probablySleepForABit();
       }
       this.cleanup();
    }
}

Стоит также отметить, что существуют библиотеки потоков / параллелизма, которые могут помочь с этим - но если у вас действительно есть несколько потоков, которые запускаются при инициализации сервлета и должны работать до тех пор, пока сервлет не будет уничтожен, это вероятно все что вам нужно.

Вопрос 2: Почему Tomcat 5.0.30 и (в более поздних версиях, включая Tomcat 6.xx) не удается правильно завершить работу, если в методе destroy () сервлета () есть System.exit ()?

Без дополнительного анализа это трудно понять наверняка. Microsoft говорит , что ошибка 1053 возникает, когда Windows запрашивает отключение службы, но время ожидания запроса истекло. Это могло бы создать впечатление, что внутри Tomcat что-то произошло, что привело его в действительно плохое состояние. Я, конечно, подозреваю, что ваш звонок System.exit() может быть виновником. Tomcat (в частности, Catalina) регистрирует завершение подключения к виртуальной машине (see org.apache.catalina.startup.Catalina.start(), по крайней мере, в 5.0.30). Этот хук отключения будет вызываться JVM при вызове System.exit(). Хук завершения работы делегируется работающим службам, поэтому потенциально может потребоваться, чтобы каждая служба выполняла много работы.

Если перехватчики завершения работы (triggered by your System.exit()) не выполняются (они тупиковые или что-то в этом роде), тогда очень легко понять, почему возникает Ошибка 1053, учитывая документацию метода Runtime.exit(int) (которая называется от System.exit()):

Если этот метод вызывается после виртуальная машина начала свое отключение Последовательность затем, если крюки выключения при запуске этот метод заблокирует на неопределенный срок. Если выключатели имеют уже был запущен и на выходе финализация была включена тогда этот метод останавливает виртуальную машину с данным кодом состояния, если статус ненулевой; в противном случае это блокирует до бесконечности.

Такое поведение "неопределенной блокировки" определенно приведет к ошибке 1053.

Если вы хотите получить более полный ответ, чем этот, вы можете скачать исходный код и отладить его самостоятельно.

Но я был бы готов поспорить, что если вы правильно решите проблему управления потоками (как описано выше), ваши проблемы исчезнут.

Короче, оставьте вызов System.exit () для Tomcat - это не ваша работа.

3 голосов
/ 13 февраля 2009

Вызов System.exit () внутри Метод уничтожения сервлета () для принудительно уничтожать любые потоки, не являющиеся демонами это хорошая идея?

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

Почему Tomcat 5.0.30 и (позже) версии, включая Tomcat 6.x.x), терпят неудачу правильно отключиться, если есть System.exit () в методе destroy () сервлета.

A много кода выполняется после удаления сервлета. Контекст уничтожает и всех других своих слушателей для одного ... другого сервлета. Другие приложения. Tomcat сам. Вызывая System.exit, вы предотвращаете запуск всего этого.

Лучший вопрос: что это за нити-демоны, почему они работают и кто их запускает?

0 голосов
/ 13 февраля 2009

При написании кода завершения потока, такого как у Джареда, я обычно делаю член keepGoing и метод stopExecuting () статическим, чтобы все потоки получали сигнал об останове за один вызов завершения работы. Хорошая идея или нет?

...