90

Linux および Windows で Java プロセスを正常に停止するにはどうすればよいですか?

いつRuntime.getRuntime().addShutdownHook呼び出され、いつ呼び出されないのですか?

ファイナライザーについてはどうですか、ここで役立ちますか?

シェルから Java プロセスに何らかのシグナルを送ることはできますか?

できればポータブルなソリューションを探しています。

4

7 に答える 7

84

シャットダウン フックは、VM が強制終了されないすべての場合に実行されます。そのため、「標準的な」kill ( SIGTERMkill コマンドから) を発行すると、それらが実行されます。同様に、これらは を呼び出した後に実行されSystem.exit(int)ます。

ただし、ハードキル (kill -9またはkill -SIGKILL) の場合は実行されません。同様に(そして明らかに)、コンピューターから電源を抜いたり、沸騰した溶岩のバットに落としたり、大ハンマーでCPUを粉々に叩いたりしても、実行されません. あなたはおそらくすでにそれを知っていました。

ファイナライザーも実際に実行する必要がありますが、シャットダウンのクリーンアップに依存するのではなく、シャットダウンフックに依存して物事をきれいに停止することをお勧めします。そして、いつものように、デッドロックには注意してください (あまりにも多くのシャットダウン フックがプロセス全体をハングさせているのを見てきました)。

于 2008-10-10T15:47:22.923 に答える
47

OK、「Java の監視と管理」で作業するために選択したすべての可能性の後、
概要はここにあります
。これにより、あるアプリケーションを別のアプリケーションから比較的簡単な方法で制御できます。制御アプリケーションをスクリプトから呼び出して、制御アプリケーションを強制終了する前に適切に停止できます。

簡略化されたコードは次のとおりです。

制御されたアプリケーション: 次
の VM パラメータで実行します:
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=9999
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management jmxremote.ssl=false

//ThreadMonitorMBean.java
public interface ThreadMonitorMBean
{
String getName();
void start();
void stop();
boolean isRunning();
}

// ThreadMonitor.java
public class ThreadMonitor implements ThreadMonitorMBean
{
private Thread m_thrd = null;

public ThreadMonitor(Thread thrd)
{
    m_thrd = thrd;
}

@Override
public String getName()
{
    return "JMX Controlled App";
}

@Override
public void start()
{
    // TODO: start application here
    System.out.println("remote start called");
}

@Override
public void stop()
{
    // TODO: stop application here
    System.out.println("remote stop called");

    m_thrd.interrupt();
}

public boolean isRunning()
{
    return Thread.currentThread().isAlive();
}

public static void main(String[] args)
{
    try
    {
        System.out.println("JMX started");

        ThreadMonitorMBean monitor = new ThreadMonitor(Thread.currentThread());

        MBeanServer server = ManagementFactory.getPlatformMBeanServer();

        ObjectName name = new ObjectName("com.example:type=ThreadMonitor");

        server.registerMBean(monitor, name);

        while(!Thread.interrupted())
        {
            // loop until interrupted
            System.out.println(".");
            try 
            {
                Thread.sleep(1000);
            } 
            catch(InterruptedException ex) 
            {
                Thread.currentThread().interrupt();
            }
        }
    }
    catch(Exception e)
    {
        e.printStackTrace();
    }
    finally
    {
        // TODO: some final clean up could be here also
        System.out.println("JMX stopped");
    }
}
}

アプリケーションの制御:コマンド ライン引数としてstopまたはstart
を指定 して実行します。

public class ThreadMonitorConsole
{

public static void main(String[] args)
{
    try
    {   
        // connecting to JMX
        System.out.println("Connect to JMX service.");
        JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://:9999/jmxrmi");
        JMXConnector jmxc = JMXConnectorFactory.connect(url, null);
        MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();

        // Construct proxy for the the MBean object
        ObjectName mbeanName = new ObjectName("com.example:type=ThreadMonitor");
        ThreadMonitorMBean mbeanProxy = JMX.newMBeanProxy(mbsc, mbeanName, ThreadMonitorMBean.class, true);

        System.out.println("Connected to: "+mbeanProxy.getName()+", the app is "+(mbeanProxy.isRunning() ? "" : "not ")+"running");

        // parse command line arguments
        if(args[0].equalsIgnoreCase("start"))
        {
            System.out.println("Invoke \"start\" method");
            mbeanProxy.start();
        }
        else if(args[0].equalsIgnoreCase("stop"))
        {
            System.out.println("Invoke \"stop\" method");
            mbeanProxy.stop();
        }

        // clean up and exit
        jmxc.close();
        System.out.println("Done.");    
    }
    catch(Exception e)
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}
}


それでおしまい。:-)

于 2008-10-16T14:36:01.690 に答える
3

これは少しトリッキーですが、移植可能なソリューションです。

  • アプリケーションにシャットダウン フックを実装する
  • JVM を正常にシャットダウンするには、 Attach APIを使用してSystem.exit()を呼び出すJava エージェントをインストールします。

Java エージェントを実装しました。Github で入手できます: https://github.com/everit-org/javaagent-shutdown

ソリューションに関する詳細な説明は、https ://everitorg.wordpress.com/2016/06/15/shutting-down-a-jvm-process/ にあります。

于 2016-06-16T08:33:10.707 に答える
2

同様の質問はこちら

Java のファイナライザーは良くありません。それらは、ガベージ コレクションに多くのオーバーヘッドを追加します。可能な限りそれらを避けてください。

shutdownHook は、VM のシャットダウン時にのみ呼び出されます。私はそれがあなたが望むことを非常によくするかもしれないと思います。

于 2008-10-10T13:23:57.393 に答える
0

Linux でのシグナル伝達は「kill」(利用可能なシグナルの man kill) で行うことができます。そのためにはプロセス ID が必要です。(ps ax | grep java) またはそのようなもの、またはプロセスが作成されたときにプロセス ID を保存します (これはほとんどの Linux スタートアップ ファイルで使用されます。/etc/init.d を参照してください)。

Java アプリケーションに SocketServer を統合することにより、移植可能なシグナリングを行うことができます。それほど難しくなく、必要なコマンドを自由に送信できます。

ファイナライザーの代わりに finally 句を意味する場合。System.exit() が呼び出されたときに実行されません。ファイナライザーは機能するはずですが、実際にはデバッグ ステートメントを出力するだけで、より重要なことを行うべきではありません。彼らは危険です。

于 2008-10-10T14:37:42.707 に答える
0

回答ありがとうございます。シャットダウン フックの縫い目は、私の場合はうまくいくようです。 しかし、 Monitoring and Management Bean と呼ばれるものにも出くわしました:
http://java.sun.com/j2se/1.5.0/docs/guide/management/overview.html
Java プロセスの。(Java 5 で導入されました)

于 2008-10-10T17:11:23.910 に答える