非Windows で動作するJava main() クラスの為に、補助するものを用意してみた。
困ったことに、Eclipse での javaw 実行では、SIGTERM シグナル送信して受け取らせることができない。
つまり
Runtime.getRuntime().addShutdownHook
で登録したスレッドの動作確認がEclipseでは困難である。
// main() クラスのための補助
public abstract class MainSupport{
/** Object Lock wait */
public static void waitLock(){
Object lock = new Object();
synchronized(lock){
try{
lock.wait();
}catch(InterruptedException e){
}
}
}
/**
* 停止フック登録
* シグナル SIGTERM を受信した時、System.exit(int)が実行されたとき、
* JVM 終了時に、引数で指定した Serviceのend()を逆の順序で実行する。
* 逆の順序で実行されることに注意
* @param services Serviceのコレクション
*/
public static void setShutdownHook(Collection<Service> services){
Runtime.getRuntime().addShutdownHook(new Thread(new _ShutdownHook(services)));
}
/* 停止フック */
public static class _ShutdownHook implements Runnable{
private ArrayList<Service> services;
public _ShutdownHook(Collection<Service> services){
this.services = new ArrayList<Service>(services);
Collections.reverse(this.services);
}
@Override
public void run(){
// shutdown time exec
for(Service service : this.services){
service.end();
}
}
}
/**
* 指定時間後に、JVM終了.
*/
public static void proceedExit(long delay){
new Timer().schedule(new _ExitProceed(),delay);
}
static class _ExitProceed extends TimerTask{
@Override
public void run(){
System.exit(0);
}
}
}
-------------------------------
public interface ServiceFactory{
public Collection<Service> create();
}
-------------------------------
public interface Service{
public void start();
public void end();
}
======== mainサンプル ============
public class Sample extends MainSupport{
public static void main(String[] args){
// ServiceFactory実装する factory を生成
// Service インスタンス生成
Collection<Service> services = factory.create();
// shutdown フック登録
setShutdownHook(services);
// Service 処理開始
for(Service service : services){
service.start();
}
// Object Lock wait
waitLock();
}
}