Pull to refresh

Обработка сигналов в Java

Reading time3 min
Views15K
Передо мной частенько вставала задача написать какой-нибудь Java-сервис. В качестве ОС мы используем по большей части линукс, так что удобнее всего управляться с такими сервисами — работать с ними как с демонами. То есть, запускаем:
start-stop-daemon --start --make-pidfile --pidfile /var/run/myservice.pid --exec /usr/bin/java — -jar myservice.jar

, и останавливаем:
start-stop-daemon --stop --quiet --oknodo --pidfile /var/run/myservice.pid

Команда --stop посылает JVM сигнал SIGTERM и сервис останавливается. Все как бы неплохо, JVM завершается в штатном порядке, если только вам не нужно выполнить по завершении работы сервиса какое-либо действие. Например явно освободить ресурс, или написать что-нибудь приятное в stdout.

Но все не так страшно, благо JVM начиная с 1.3.1 позволяет обрабатывать сигналы. За ответом как — под хабракат.

Для обработки сигналов я в свое время написал простой вспомогательный класс:
import sun.misc.Signal;
import sun.misc.SignalHandler;

public class DiagnosticSignalHandler implements SignalHandler {

  // Static method to install the signal handler
  public static void install(String signalName, SignalHandler handler) {
    Signal signal = new Signal(signalName);
    DiagnosticSignalHandler diagnosticSignalHandler = new DiagnosticSignalHandler();
    SignalHandler oldHandler = Signal.handle(signal, diagnosticSignalHandler);
    diagnosticSignalHandler.setHandler(handler);
    diagnosticSignalHandler.setOldHandler(oldHandler);
  }
  private SignalHandler oldHandler;
  private SignalHandler handler;

  private DiagnosticSignalHandler() {
  }

  private void setOldHandler(SignalHandler oldHandler) {
    this.oldHandler = oldHandler;
  }

  private void setHandler(SignalHandler handler) {
    this.handler = handler;
  }

  // Signal handler method
  @Override
  public void handle(Signal sig) {
    System.out.println("Diagnostic Signal handler called for signal " + sig);
    try {
      handler.handle(sig);

      // Chain back to previous handler, if one exists
      if (oldHandler != SIG_DFL && oldHandler != SIG_IGN) {
        oldHandler.handle(sig);
      }

    } catch (Exception e) {
      System.out.println("Signal handler failed, reason " + e);
    }
  }
}


* This source code was highlighted with Source Code Highlighter.

Пример использования:
import sun.misc.Signal;
import sun.misc.SignalHandler;

public class App {
  private SomeVeryImportantResource resource;

  public static void main(String[] args) {
    SignalHandler signalHandler = new SignalHandler() {
      @Override
      public void handle(Signal sig) {
        ...
        resource.release();
        ...
      }
    };
    DiagnosticSignalHandler.install("TERM", signalHandler);
    DiagnosticSignalHandler.install("INT", signalHandler);
    DiagnosticSignalHandler.install("ABRT", signalHandler);
    ...
    resource.lock();
    ...
  }
}


* This source code was highlighted with Source Code Highlighter.

Вот и все, ничего сложного. В handler'е совершаем необходимые действия и приложение завершается.

В топике я привел самый простой вариант использования — отлавливаем SIGINT, SIGTERM и SIGABRT. На самом деле различных видов сигналов, как и вариантов их использования, намного больше. Более подробное описание смотреть здесь:
http://www.ibm.com/developerworks/ibm/library/i-signalhandling/
Tags:
Hubs:
Total votes 38: ↑29 and ↓9+20
Comments10

Articles