37

Java の ProcessBuilder を使用して、Linux で「長期間」実行する必要があるアプリケーションを起動しようとしています。このプログラムの実行方法は、コマンドを起動し (この場合、メディア再生アプリケーションを起動しています)、実行を許可し、クラッシュしていないことを確認します。たとえば、PID がまだアクティブかどうかを確認し、プロセスが停止している場合はプロセスを再起動します。

私が今抱えている問題は、PID はシステム内で有効なままですが、アプリケーションの GUI がハングすることです。ProcessBuilder(cmd).start() を別のスレッドにシフトしようとしましたが、期待どおりに何も解決していないようです。

基本的に、結果として、ユーザーにはプログラムがクラッシュしたように見えますが、ProcessBuilder.start() プロセスを駆動する Java プロセスを強制終了すると、実際には、作成されたプロセスが通常の動作を再開できるようになります。これは、Java アプリケーション内の何かが生成されたプロセスに干渉していることを意味しますが、現時点では何が原因かまったくわかりません。(したがって、何も解決していないように見える別のスレッドに分けようとした理由)

誰かが意見や考えを持っている場合は、私に知らせてください。私は一生、この問題を解決する方法を考えることができません。

編集: プロセスから作成された I/O ストリームについて心配していないため、それに対処するための措置を講じていません。これにより、プロセス自体がハングする可能性がありますか?

4

10 に答える 10

44

プロセスがstderrまたはstdoutに書き込み、それを読み取っていない場合、単に「ハング」し、に書き込むときにブロックされstdout/errます。シェルstdout/errを使用するようにリダイレクトするか、redirectErrorStream(true)とマージして、プロセスから読み取る別のスレッドを生成します/dev/nullstdout/errstdout

于 2010-07-19T22:06:18.843 に答える
12

あなたトリックが欲しいですか?

ProcessBuilder.start()からプロセスを開始しないでください。Java からのストリームのリダイレクト/消費を台無しにしようとしないでください (特に、それについて何も言わない場合は ; )

ProcessBuilder.start()を使用して、すべての入出力ストリームを処理する小さなシェル スクリプトを開始します。

そんな感じ:

#!/bin/bash

nohup $1 >/dev/null 2>error.log &

つまり、stdout を気にせず、それでも stderr をファイル (ここではerror.log ) に記録したい場合です。

stderr を気にしない場合は、stdout にリダイレクトしてください。

#!/bin/bash

nohup $1 >/dev/null 2>1 &

そして、実行したいプロセスの名前を引数として渡して、Java からその小さなスクリプトを呼び出します。

stdout と stderr の両方を /dev/null にリダイレクトしている Linux で実行されているプロセスがまだ何かを生成する場合は、壊れた非準拠の Linux インストールがあります;)

言い換えれば、上記の Just Works [TM] は、「この順序でストリームを消費する必要があり、Java 固有のナンセンス」という問題を取り除きます。

于 2010-07-19T22:46:27.840 に答える
11

プロセスを実行しているスレッドは、出力を処理しない場合、ブロックされる可能性があります。これは、プロセスの出力を読み取る新しいスレッドを生成することで実行できます。

    final ProcessBuilder builder = new ProcessBuilder("script")
                    .redirectErrorStream(true)
                    .directory(workDirectory);

    final Process process = builder.start();
    final StringWriter writer = new StringWriter();

    new Thread(new Runnable() {
        public void run() {
            IOUtils.copy(process.getInputStream(), writer);
        }
    }).start();

    final int exitValue = process.waitFor();
    final String processOutput = writer.toString();
于 2012-10-15T10:45:53.443 に答える
6

同様の問題が発生した後、これに出くわしました。nos に同意して、出力を処理する必要があります。私はこのようなものを持っていました:

ProcessBuilder myProc2 = new ProcessBuilder(command);
final Process process = myProc2.start();

そしてそれはうまく機能していました。生成されたプロセスは、いくらかの出力を出力しましたが、それほど多くはありませんでした。より多くの出力を開始したとき、私のプロセスはもはや起動されていないように見えました。私はこれに更新しました:

ProcessBuilder myProc2 = new ProcessBuilder(command);
myProc2.redirectErrorStream(true);        
final Process process = myProc2.start();
InputStream myIS = process.getInputStream();
String tempOut = convertStreamToStr(myIS);

そしてそれは再び働き始めました。( convertStreamToStr() コードについては、このリンクを参照してください)

于 2011-12-07T16:51:23.137 に答える
3

編集: プロセスから作成された I/O ストリームについて心配していないため、それに対処するための措置を講じていません。これにより、プロセス自体がハングする可能性がありますか?

プロセスによって作成された出力ストリームを読み取らない場合、アプリケーションのバッファがいっぱいになると、アプリケーションがブロックされる可能性があります。私はこれが Linux で起こるのを見たことがありません (そうでないと言っているわけではありませんが) が、Windows でこの正確な問題を見たことがあります。これが関係している可能性が高いと思います。

于 2010-07-19T22:03:13.897 に答える
3

JDK7 には、サブプロセス I/O リダイレクトのサポートが組み込まれています。

http://download.oracle.com/javase/7/docs/api/java/lang/ProcessBuilder.html

それまでの間、本当に stdout/stderr を破棄したい場合は、(Linux では) 次のようなコマンドで ProcessBuilder を呼び出すのが最善のようです。

["/bin/bash", "-c", "exec YOUR_COMMAND_HERE >/dev/null 2>&1"]
于 2011-04-11T16:03:50.970 に答える
0

stdout と stderr をキャプチャしてプロセスを監視する必要がある場合は、Apache Commons Execを使用すると非常に役立ちました。

于 2016-08-02T20:38:56.083 に答える