Linux および Windows で Java プロセスを正常に停止するにはどうすればよいですか?
いつRuntime.getRuntime().addShutdownHook
呼び出され、いつ呼び出されないのですか?
ファイナライザーについてはどうですか、ここで役立ちますか?
シェルから Java プロセスに何らかのシグナルを送ることはできますか?
できればポータブルなソリューションを探しています。
シャットダウン フックは、VM が強制終了されないすべての場合に実行されます。そのため、「標準的な」kill ( SIGTERM
kill コマンドから) を発行すると、それらが実行されます。同様に、これらは を呼び出した後に実行されSystem.exit(int)
ます。
ただし、ハードキル (kill -9
またはkill -SIGKILL
) の場合は実行されません。同様に(そして明らかに)、コンピューターから電源を抜いたり、沸騰した溶岩のバットに落としたり、大ハンマーでCPUを粉々に叩いたりしても、実行されません. あなたはおそらくすでにそれを知っていました。
ファイナライザーも実際に実行する必要がありますが、シャットダウンのクリーンアップに依存するのではなく、シャットダウンフックに依存して物事をきれいに停止することをお勧めします。そして、いつものように、デッドロックには注意してください (あまりにも多くのシャットダウン フックがプロセス全体をハングさせているのを見てきました)。
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();
}
}
}
それでおしまい。:-)
これは少しトリッキーですが、移植可能なソリューションです。
Java エージェントを実装しました。Github で入手できます: https://github.com/everit-org/javaagent-shutdown
ソリューションに関する詳細な説明は、https ://everitorg.wordpress.com/2016/06/15/shutting-down-a-jvm-process/ にあります。
同様の質問はこちら
Java のファイナライザーは良くありません。それらは、ガベージ コレクションに多くのオーバーヘッドを追加します。可能な限りそれらを避けてください。
shutdownHook は、VM のシャットダウン時にのみ呼び出されます。私はそれがあなたが望むことを非常によくするかもしれないと思います。
Linux でのシグナル伝達は「kill」(利用可能なシグナルの man kill) で行うことができます。そのためにはプロセス ID が必要です。(ps ax | grep java) またはそのようなもの、またはプロセスが作成されたときにプロセス ID を保存します (これはほとんどの Linux スタートアップ ファイルで使用されます。/etc/init.d を参照してください)。
Java アプリケーションに SocketServer を統合することにより、移植可能なシグナリングを行うことができます。それほど難しくなく、必要なコマンドを自由に送信できます。
ファイナライザーの代わりに finally 句を意味する場合。System.exit() が呼び出されたときに実行されません。ファイナライザーは機能するはずですが、実際にはデバッグ ステートメントを出力するだけで、より重要なことを行うべきではありません。彼らは危険です。
回答ありがとうございます。シャットダウン フックの縫い目は、私の場合はうまくいくようです。
しかし、 Monitoring and Management Bean と呼ばれるものにも出くわしました:
http://java.sun.com/j2se/1.5.0/docs/guide/management/overview.html
Java プロセスの。(Java 5 で導入されました)