ぺーぺーSEのブログ

備忘録・メモ用サイト。

Javaでシグナルを捕まえる方法

Linuxのkillコマンドなどで投げるシグナルをJavaで捕まえる方法について。
下記、シグナルを捕まえたらlog4jのログレベルを変更するコードを書いてみた。

package jp.sample.signal.log4j.main;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.Level;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

import sun.misc.Signal;
import sun.misc.SignalHandler;

public class SignalLog4jMain {

  static Log log = LogFactory.getLog(SignalLog4jMain.class);
  static int num = 1;

  public static void main(String[] args) {
    Signal signal = new Signal("TERM");
    System.out.println("Default Signal Number: " + signal.getNumber());
    Signal.handle(signal, new SignalHandler() {
      public void handle(Signal signal) {
        Logger rootLogger = LogManager.getRootLogger();
        if (rootLogger.getLevel().equals(Level.INFO)) {
          rootLogger.setLevel(Level.DEBUG);
        } else {
          rootLogger.setLevel(Level.INFO);
        }
        num++;
      }
    });

    while (true) {
      try {
        Thread.sleep(5000);
        Logger rootLogger = LogManager.getRootLogger();
        System.out.println("Log Level: " + rootLogger.getLevel());
        if (log.isDebugEnabled()) {
          log.debug("DEBUG LOG !!\n");
        }
        if (log.isInfoEnabled()) {
          log.info("INFO LOG !!\n");

        }
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }
}

5秒毎にログを吐く。
下記でアプリケーションに対してシグナルを投げる。

kill -TERM [JavaアプリのPID]

シグナルはソースコード中でシグナル名で設定している。

Signal signal = new Signal("TERM");

Linuxでは「kill -l」を実行すると下記のようにシグナルの一覧が表示される。

$ kill -l
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL
 5) SIGTRAP      6) SIGABRT      7) SIGBUS       8) SIGFPE
 9) SIGKILL     10) SIGUSR1     11) SIGSEGV     12) SIGUSR2
13) SIGPIPE     14) SIGALRM     15) SIGTERM     17) SIGCHLD
18) SIGCONT     19) SIGSTOP     20) SIGTSTP     21) SIGTTIN
22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO
30) SIGPWR      31) SIGSYS      35) SIGRTMIN    36) SIGRTMIN+1
37) SIGRTMIN+2  38) SIGRTMIN+3  39) SIGRTMIN+4  40) SIGRTMIN+5
41) SIGRTMIN+6  42) SIGRTMIN+7  43) SIGRTMIN+8  44) SIGRTMIN+9
45) SIGRTMIN+10 46) SIGRTMIN+11 47) SIGRTMIN+12 48) SIGRTMIN+13
49) SIGRTMIN+14 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8
57) SIGRTMAX-7  58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4
61) SIGRTMAX-3  62) SIGRTMAX-2  63) SIGRTMAX-1  64) SIGRTMAX

この一覧では「SIG〜」のような名前で表示される。
実際にkillコマンドでシグナルを投げる際は「SIG」を外して指定する必要があることに注意。
例えば「SIGHUP」のシグナルを送りたいときは、「kill -HUP [PID]」と実行する必要がある。
また、HotSpotVMは下記のシグナルを使用しており、アプリケーションでシグナルを使用したい場合には下記を避けて選択する必要がある。

  • SIGSEGV
  • SIGBUS
  • SIGFPE
  • SIGPIPE
  • SIGILL
  • SIGQUIT
  • SIGTERM
  • SIGUSR1
  • SIGUSR2
  • SIGABRT

ソース:http://www.oracle.com/technetwork/java/javase/signals-139944.html

Linuxのシグナルまとめ
http://www.xmisao.com/2013/11/10/linux-kill-signals.html