Javaにおけるサブプロセスの待ち方

このQ&Aのポイント
  • Javaでサブプロセスを実行し、標準出力から文字列を取得するプログラムがフリーズする現象が発生します。
  • フリーズする原因は、サブプロセスの終了を待つps.waitFor()メソッドで止まっているためです。
  • この現象は、特定の条件下で起こる可能性があり、Javaのバグである可能性があります。
回答を見る
  • ベストアンサー

javaにおけるサブプロセスの待ち方

以下のコードで問題が起きました。 javaからサブプロセスを読んで、サブプロセスの標準出力から 文字列を取得するプログラムです。 //Inter.java import java.io.*; public class Inter { static final int A = 10; public static void main(String[] arg) { String out = "Initial"; int c; Runtime rt = Runtime.getRuntime(); try{ Process ps = rt.exec("process.exe"); BufferedReader br = new BufferedReader(new InputStreamReader(ps.getInputStream())); System.out.println("Debug:OK"); for(c=0;c < A;c++)//ポイント1 { out = br.readLine(); System.out.println("java:" + out); } out = Integer.toString(ps.waitFor());//ポイント2 System.out.println("終了コード:" + out); }catch(Exception ex){ System.out.println("エラー"); } System.out.println("正常終了"); } } 一方呼び出されるサブプロセスは //process.c //compiled to process.exe #include <stdio.h> int main () { int i,k,n; for(i=0;i<100;i++) { printf("test%d\n",i); } return 235; } ここで、java側のコードの定数Aを1以上に設定るると期待どおりの結果が出るのですがA=0つまり、for文に一度も入らず、標準出力のストリームから文字列を一度も読まないとフリーズします。どうやら out = Integer.toString(ps.waitFor());//ポイント2 の部分で止まるようです。これはなぜでしょうか?これでは、標準出力があるサブプロセスの終了コードだけ知りたい時に不便ではないですか?これはもしやjava言語システムのバグではないでしょうか!waitFor()メソッドの実装が観たいのですがあいにくnativeキーワードがあるメソッドで手元のソースだけではでは中身がわかりません。nativeのさらに中の実装は見ることはできないのでしょうか?

  • Java
  • 回答数2
  • ありがとう数1

質問者が選んだベストアンサー

  • ベストアンサー
  • root139
  • ベストアンサー率60% (488/809)
回答No.2

Process の各 InputStream の読込みを行わないと、子プロセスの標準出力または標準エラー出力のデータ量が多い場合にバッファーが満杯になり、ブロックしてしまうことが有ります。 ↓の「ネイティブなプラットフォームには・・・」の部分を参照して下さい。 http://java.sun.com/javase/ja/6/docs/ja/api/java/lang/Process.html 仕様・・・というか、その様な実装が許されていることになるのかと。 また、バッファーサイズは個々のJVMの実装によると思いますが、かなり小さいことが多いようです。 標準出力/標準エラー出力それぞれの読込みスレッドを作って読込ませることで一応の解決にはなります。 確かに不便ですね・・・。 下記のページも参考になるかと。 http://www.ne.jp/asahi/hishidama/home/tech/java/process.html#h4_NG_after http://blog.livedoor.jp/applepedlar/archives/51979434.html http://isolinear.info/wiki/index.php/Java/Tips/Java%A4%C7%A1%A4%BB%D2%A5%D7%A5%ED%A5%BB%A5%B9%A4%F2%BB%C8%A4%A6%A4%C8%A4%AD%A4%CE%C3%ED%B0%D5%C5%C0.html

KSnake
質問者

お礼

ご回答ありがとうございます。 とりあえず、別スレッドを使って読むことに成功しました。

その他の回答 (1)

回答No.1

参考程度に読んでください。 最近はJavaから離れているので定かではないのですが、Windowsプラットフォームでは別スレッドでストリームを読んでやる必要があったような気がします。 Java1.5頃の開発なので最近は違うかもしれませんがWindowsではプロセスの制御がうまくなく(Javaかも)別スレッドにしてやらないとデッドロックになったと記憶しています。 苦労した記憶が残っているのでやってみる価値が少しはあると思います。 参考まで。

関連するQ&A

  • javaについて

    以下のようにキーボードから入力していくプログラムを試行しているのですが、エラーが出てくるので行き詰まっています。 理想的にはキーボードに”あいう”エンター”えおか”エンターと打ち込んだら str[0]=あいう str[1]=えおか と表示させていきたいのですが、よろしくお願いします。 import java.io.*; import java.lang.*; import java.net.*; import java.awt.*; class gugu2 { public static void main(String[] args) throws IOException { int i=0; while(i<2){ System.out.println("キーワード入力"); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String input = br.readLine(); char str[] = input.toCharArray(); System.out.println("キーワードは" + str[]); i=i+1; } for(i=0;i<2;i++){ System.out.println(str[]); } } } これがエラー表示です。 gugu2.java:17: '.class' がありません。 System.out.println("キーワードは" + str[]); ^ gugu2.java:21: '.class' がありません。 System.out.println(str[]); ^ エラー 2 個

    • ベストアンサー
    • Java
  • JAVAのプログラムについて

    独学でJAVAを勉強中なのですが、 import java.io.*; public class ExserciseD5L3_2{ public static void main(String args[]){ BufferedReader br = new BufferedReader(newInputStreamReader(System.in),1); try{ System.out.println("■■■計算クイズ■■■"); System.out.println("計算してください。"); String Que[] = {"10×50=?","21-7=?","360÷6=?"}; int Ans[] = {500,14,60}; int counter; for(counter = 0; counter <=2; counter++ ){ System.out.println(Que[counter]); System.out.println("答えは?"); String str = br.readLine(); int i = Integer.parseInt(str); if(i == Ans[counter]){ System.out.println("おめでとう!大当たりです。"); } else{ System.out.println("残念!答えは"+Ans[counter]+"です。"); } } } catch(IOException e){ System.out.println("IOエラーが発生しました。"); } catch(NumberFormatException ne){ System.out.println("入力された数値が正しくないようです。"); } } } これを実行すると ■■■計算クイズ■■■ 計算してください。 10×50=? 答えは? 500 おめでとう!大当たりです。 21-7=? 答えは? 14 おめでとう!大当たりです。 360÷6=? 答えは? 60 おめでとう!大当たりです。 となるのですが、これに おめでとう!正解数は3つです。とか正解数は2つですなどのように 正解数も出るようにするにはどのようにしたらいいのでしょうか?

    • ベストアンサー
    • Java
  • Java trimの設定について

    Java trimの設定についてお伺いいたします。 最高気温と最低気温を表示することができずに困っております。trimをどのように設定すれば良いかご教授お願いします。 以下、ソースを記載します。 import java.io.*; public class Sample { public static void main(String[] args) { try{ BufferedReader br = new BufferedReader(new FileReader("kion.txt")); System.out.println("気温データ出力"); int test[] = new int[4]; String str; for(int i=0;i<test.length;i++){ str = br.readLine(); } int max = 0; int min = 0; for(int i=0;i<test.length;i++){ if(max < test[i]) max = test[i]; if(min > test[i]) min = test[i]; System.out.println(test[i]); } System.out.println("最高気温" + max + "です。"); System.out.println("最低気温" + min + "です。"); br.close(); } catch(IOException e){ System.out.println("入出力エラーです"); } } } また「kion.txt]は 東京 30.2 18.5 神奈川 34.2 18.5 埼玉 29.8 16.4 千葉 27.5 14.7 と作成しました。 これを 最高気温 神奈川 34.2 最低気温 千葉  14.7 と表示したいのですが、現在は「0 0 0 0」と表示するだけです。 何卒、よろしくお願い致します。

  • javaについて・・・

    このように出力されるプログラムを考えています ↓ 受験者人数を入力してください 3 3人分の点数を入力してください 50 80 20 1人目の点数は50です 2人目の点数は80です 3人目の点数は20です 最高点は80です っという感じのプログラムを考えています。 そしていまここまでプログラムを書いたのはいいのですが 感じんの最高点が表示されません・・・ import java.io.*; class test{ public static void main(String[] args) throws IOException{ System.out.println("テストの受験者数を入力してください。"); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String str =br.readLine(); int num = Integer.parseInt(str); int test[] = new int[num]; int max=0; System.out.println(test.length +"人の点数を入力してください"); for(int i=0; i<num; i++){ String str1 = br.readLine(); test[i] = Integer.parseInt(str1); } for(int i=0; j<num; i++){ System.out.println((i+1)+"番目の人の点数は"+ test[i]+"です。"); if(test[i]>max){ max=test[i]; } } System.out.println("最高点は" +max+ "です。"); } } どこをどのように直せば最高点が表示されるようになるでしょうか? ご指摘おねがいします。

  • Javaの文字コード変換方法

    文字コードの変換で困っています。 例えば、標準入力で「あいう」と入力して、その文字列を UTF-8に変換して出力したいのですが、うまくいきません。 サイトにはbyteに変換してから入れると書いていましたが、 よくわかりませんでした。 宜しくお願いします。 以下、今できているソースです。 (ソースコード) import java.io.*; public class ChangeCord { public static void main( String[] args ) { try { System.out.println("何か日本語を入力してください。"); BufferedReader br = new BufferedReader( new InputStreamReader(System.in, "UTF-8")); String str = br.readLine(); System.out.println("文字コードUTF-8に変換した結果"); System.out.println(str); }catch (Exception e) { System.out.println("エラー"); } } } (出力結果) 何か日本語を入力してください。 あいう 文字コードUTF-8に変換した結果 ?????? 以上です。

    • ベストアンサー
    • Java
  • javaについて質問です。

    javaについて質問です。 シーザー暗号の暗号化と復号化のプログラムをつくりたいのですが... import java.io.*; class Prob6_2 { public static void main(String [] args)throws IOException { int key; //キー番号 String orgStr; //ターゲット文字列 String encStr; //暗号化文字列 String decStr; // 復号化文字列 String temp; BufferedReader br= new BufferedReader(new InputStreamReader(System.in)); System.out.print("ターゲット文字列:"); orgStr=br.readLine(); System.out.print("キー番号:"); temp=br.readLine(); key=Integer.parseInt(temp); Cipher cip=new Cipher (); encStr=cip.encrypt(orgStr,key); decStr=cip.decrypt(encStr,key); System.out.println("[Original Code]"+orgStr); System.out.println("[Encrypted Code]"+encStr); System.out.println("[Decrypted Code]"+decStr); } } class Cipher { String encrypt(String str,int key) { for(int i=0;i<str.length();i++){ char c=str.charAt(i); c=(char)((int)c+key); /*この後どのように一つずつの文字をつなげて文字列にしたら良いか分かりません。StringBuffer クラスのインスタンス をつかうといいというヒントは問題集に書いてあるのですが....教えて下さい*/ } } String decrypt(String str,int key) { for(int i=0;i<str.length();i++){ char c=str.charAt(i); c=(char)((int)c-key); /*この後どのように一つずつの文字をつなげて文字列にしたら良いか分かりません。StringBuffer クラスのインスタンス をつかうといいというヒントは問題集に書いてあるのですが....教えて下さい*/ } } } class Cipherのところにコメントでも書いてあるのですが、一つずつの文字をつなげて文字列にしたら良いか分かりません。どのように実現したら良いのでしょうか?><教えてください>< 違っているところがあればそこも教えて頂けるとたすかります。 お願いします>< できたらStringBufferをつかったやり方を教えてください><」

    • ベストアンサー
    • Java
  • Javaについて教えてください。

    Javaのソースコードで以下のコードを実行すると表示されないのですがなぜでしょうか? public class Sample{ public static void main(String[] args){ for (int i = 0 ; i >= 5; i++){ System.out.println(i); } } }

  • Javaのプログラムで・・・

    Javaのプログラムで1~20までの整数乱数を実行後に指定回数だけ発生させ、そのうち何%が奇数であったかを表示するプログラムを作成中です。 乱数を発生させるところまでは行ったのですがここからどのように計算していくのかわかりません。 以下が作成したものですがアドバイスお願いします。 import java.io.*; public class Rand { public static void main(String args[]) throws IOException { System.out.print("発生させる乱数の回数は?"); BufferedReader br= new BufferedReader(new InputStreamReader(System.in)); String str = br.readLine(); int num= Integer.parseInt(str); for(int i=1;i<=num;i++){ int a=(int)(20*Math.random()+1); System.out.println(a); } for(int a=1; a<=;a++){ if(a%2==1); System.out.println("発生した乱数の"++"%が奇数です。"); } } }

  • 初心者Javaの件。

    いつも大変お世話になりありがとうございます。 次の2つのコードは関係があるのでしょうか? 2つを合体させないとプログラムがエラーになるのでしょうか? 私は合体させないとプログラムが成立しないと思います。 アドバイスのほど宜しくお願い申し上げます。 コード1 public class Person { private int age; private double weight; private double height; public Person(int age, double weight, double height) { this.age = age; this.weight = weight; this.height = height; } public void show() { System.out.println("年齢は" + age + "体重は" + weight + "身長は"+ height +"です。" ); } } コード2 import java.io.BufferedReader; public class Sample3 { { public static void main(String args[]) throws Exception { person p[]; System.out.println("人数を入力してください。"); BufferedReader br = new BufferedReader(new inputStreamReader(System.in)); String str = br.readLine(); int num = Integer.parseInt(str); p = new Person[num]; for(int i=0; i<num; i++) { } System.out.println("年齢を入力してください"); str = br.readLine(); int age = Integer.parseInt(str); P = new Person[num]; for(int i=0; i<num; i++){ System.out.println("年齢を入力してください"); str = br.readLine(); int age = Intger.parseInt(str); System.out.println("体重を入力してください"); str = br.readLine(); double weight = Double.parseDouble(str); System.out.println("身長を入力してください"); str = br.readLine(); double height = Double.parseDouble(str); p[i] = new person(age, weight, height); } for(int i=0; i<num; i++) { p[i].show(); } } }

    • ベストアンサー
    • Java
  • javaについて質問です。お願いします><

    javaについて質問です。お願いします>< シーザー暗号を実現するプログラムをじゃいたのですが、import java.io.*; class Prob6_3 { public static void main(String [] args)throws IOException { int key; //キー番号 String orgStr; //ターゲット文字列 String encStr; //暗号化文字列 String decStr; // 復号化文字列 String temp; BufferedReader br= new BufferedReader(new InputStreamReader(System.in)); System.out.print("ターゲット文字列:"); orgStr=br.readLine(); System.out.print("キー番号:"); temp=br.readLine(); key=Integer.parseInt(temp); Cipher cip=new Cipher (); encStr=cip.encrypt(orgStr,key); decStr=cip.decrypt(encStr,key); System.out.println("[Original Code]"+orgStr); System.out.println("[Encrypted Code]"+encStr); System.out.println("[Decrypted Code]"+decStr); } } class Cipher { String encrypt(String str,int key) { String ret="";             //ココです1 for(int i=0;i<str.length();i++){ char c=str.charAt(i); c=(char)((int)c+key); ret+=c; } return ret; } String decrypt(String str,int key) { String ret="";              //ここです2 for(int i=0;i<str.length();i++){ char c=str.charAt(i); c=(char)((int)c-key); ret+=c; } return ret; } }   とこんな感じになり実行もできるのですが、class CipherのString encrypt(String str,int key)やString decrypt(String str,int key)のところで一つずつ文字をつなげて文字列にするにはStringBufferクラスのインスタンスを利用すると簡単だとききました。だけど記述方法がよくわからなく使用した場合のreturn文の書き方もイマイチわかりません><なのでできるだけ詳しく教えて頂けないでしょうか??お願いします。//ココですと書いてあるところです。お願いします><

    • ベストアンサー
    • Java

専門家に質問してみよう