2017-02-08 25 views
3

Taskで呼び出されたサードパーティのJavaライブラリがExecutorServiceに送信されているとします。無限ループの場合にExecutorServiceに送信されたタスクでサードパーティのJavaコードを処理する方法

私はサードパーティのライブラリが悪意のあるものではないと信じていますが、無限ループに陥る可能性のあるプログラミングエラーが存在することはまれであり、その場合は修正できませんそのまれな出来事に対処する。

これを処理する最良の方法は、アプリケーションが停止しないようにすることです。 shutdownNow()はこの状況を処理するのに十分ですか?

関連する問題Stop an infinite loop in an ExecutorService taskがありますが、これはプログラマが協調して処理することを頼りにして処理を停止することに依存しています。

(私の場合、それはJythonのコードです;。、Jythonのthe interpreter apparently didn't check Thread.currentThread().isInterrupted()の初期のバージョンでは、それは今何をするかわからない...しかし、私の質問は、任意のサードパーティ製のJavaコードのために一般的である)

+0

hmmm .. http://stackoverflow.com/questions/10853305/how-to-stop-long-duration-execution-task-例えば、無限ループ実行のようなものですが、わかりません。 –

+0

"割り込み中にループチェック状態にする" - そのようなループが存在する場合は、サードパーティのコードにあります。 –

+1

@efekctiveほとんど違いはありません。メソッドを実行可能ファイルにラップすると、 'run(){run3rdParty(); } '' run3rdParty'は決して戻りません。あなたができることはあまりありません:割り込みチェックを挿入すると、実行されません。 – assylias

答えて

1

場合、タスクスレッドの中断状態をチェックせず、InterruptedExceptionをスローするメソッドを使用しない無限ループを持っています。shutdownNow()によって停止されません。

あなたのプログラムが終了することはできません

簡単な例:

public static void main(String[] args) throws Exception { 
    ExecutorService e = Executors.newFixedThreadPool(1); 
    e.submit(() -> { while (true); }); 
    e.shutdownNow(); 
    System.out.println("Main is finished but the app keeps running"); 
} 

一つの方法は、デーモンとしてスレッドを実行するために、次のようになります。質問の私の正しい読みに続き

public static void main(String[] args) throws Exception { 
    ExecutorService e = Executors.newFixedThreadPool(1, r -> { 
     Thread t = new Thread(r); 
     t.setDaemon(true); 
     return t; 
    }); 
    e.submit(() -> { while (true); }); 
    e.shutdownNow(); 
    System.out.println("Main is finished and the app can exit"); 
} 
+0

ええと、これはJVMのライフサイクルが呼び出し元のライフサイクルと同じ場合に機能しますが、プラグインでJVMがゾンビデーモンスレッド。 –

+0

@ JasonSアプリケーションが実行中であれば、中断できない場合でもタスクは実行され続けます。 – assylias

+0

grrrr。セキュリティ権限に支払うすべての注意を払って、Javaでこのように動作することに驚いた。 –

1

をIこのクラスの集合をまとめる。比較的シンプル:入力を送信するソケットに接続し、不安定なライブラリを呼び出すセカンダリjvmから出力を取得する1つのRunnable。

3回の試行後に応答が受信されなかった場合、2次jvmが強制終了されます。しかし、それは再開することができます。セカンダリjvmには、ソケットを閉じるexitフックがあります。

class SafetyValve implements Runnable{ 
    PrintWriter out; 
    BufferedReader in; 
    Socket s = null; 

    AtomicBoolean flag; 

    SafetyValve(AtomicBoolean b){ 
     flag = b; 
    } 
    @Override 
    public void run() { 
     try { 
      s = new Socket("localhost", 9000); 
      out = new PrintWriter(s.getOutputStream(), true); 
      in = new BufferedReader(new InputStreamReader(s.getInputStream())); 

      while (!Thread.currentThread().isInterrupted()){ 
       flag.set(false); 
       out.print(0); 
       out.flush(); 
       System.out.print(in.read()); 
       flag.set(true); 
      } 

     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
     finally{ 
      try { 
       s.close(); 
      } catch (IOException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
     } 
    } 

} 

メイン/コントローラクラス。

class UnYielding{ 
    int i = 0; 

    int returnInt(){ 
     i++; 
     if (i > 2) 
      while(true); 
     return i; 
    } 
} 

class Hook extends Thread{ 

    RunWild rw; 

    Hook(RunWild wr){ 
     rw = wr; 
    } 

    public void run() { 
     try { 
      System.out.println("exit..."); 
      System.out.flush(); 
      rw.socket.close(); 
      rw.server.close(); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 

} 

public class RunWild { 

    ServerSocket server; 
    Socket socket; 

    RunWild(){ 
     Runtime.getRuntime().addShutdownHook(new Hook(this)); 
    } 

    public static void main(String[] args){ 
     UnYielding u; 
     int i; 
     PrintWriter out; 
     BufferedReader in; 
     RunWild rw = new RunWild(); 

     try { 
      rw.server = new ServerSocket(9000); 
      rw.socket = rw.server.accept(); 
      out = new PrintWriter(rw.socket.getOutputStream(), true); 
      in = new BufferedReader(new InputStreamReader(rw.socket.getInputStream())); 
      u = new UnYielding(); 
      while ((i = in.read()) != -1){ 
       out.print(u.returnInt()); 
       out.flush(); 
       Thread.sleep(10); 
       System.out.print("waiting..."); 
       System.out.flush(); 
      } 

     } catch (Exception e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 

    } 

} 

私は期待どおりに動作するOS X上1.8に対してこれをテストしている:それは、二次JVMが標準のサーバソケット実装を持っている

public class Switch { 
    public static void main(String[] args) { 
     try { 
      AtomicBoolean flag = new AtomicBoolean(false); 
      int counter = 0; 
      ProcessBuilder pb = ... 
      pb.directory(,,,); 
      Process p = pb.start(); 
      SafetyValve sv = new SafetyValve(flag); 
      Thread t = new Thread(sv); 
      t.start(); 
      while(t.getState() != Thread.State.RUNNABLE){ 
       Thread.sleep(10); 
      } 
      while(true){ 
       if (flag.get() == false){ 
        if (++counter == 3){ 
         while(t.getState() != Thread.State.TERMINATED){ 
          p.destroyForcibly(); 
          t.interrupt(); 
          Thread.sleep(10); 
         } 
         break; 
        } 
       } 
       else 
        counter = 0; 
       Thread.sleep(100); 
      } 

     } catch (Exception e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 
} 

制御

のためのThreadクラスを使用しています。この不安定なクラスが必要な場合は、これを行う1つの方法です

関連する問題