2016-11-16 17 views
2

私はいくつかのリソースを "閉じる"より良い方法を探しています、ここでは外部Processを破棄し、CompletableFutureのチェーンにあります。今私のコードは、おおよそ次のようになります。私は見CompletableFutureチェーンの外部プロセスを閉じる

public CompletableFuture<ExecutionContext> createFuture() 
{ 
    final Process[] processHolder = new Process[1]; 
    return CompletableFuture.supplyAsync(
      () -> { 
       try { 
        processHolder[0] = new ProcessBuilder(COMMAND) 
          .redirectErrorStream(true) 
          .start(); 
       } catch (IOException e) { 
        throw new UncheckedIOException(e); 
       } 
       return PARSER.parse(processHolder[0].getInputStream()); 
      }, SCHEDULER) 
      .applyToEither(createTimeoutFuture(DURATION), Function.identity()) 
      .exceptionally(throwable -> { 
       processHolder[0].destroyForcibly(); 
       if (throwable instanceof TimeoutException) { 
        throw new DatasourceTimeoutException(throwable); 
       } 
       Throwables.propagateIfInstanceOf(throwable, DatasourceException.class); 
       throw new DatasourceException(throwable); 
      }); 
} 

問題は、それがエラーの場合に閉鎖することができるように、プロセスへの参照を保持している「ハック」1要素の配列です。いくつかの "コンテキスト"をexceptionally(またはそれを達成するための他の方法)に渡すことを可能にするいくつかのCompletableFuture APIがありますか?

私はカスタムCompletionStageの実装を考えていましたが、 "ホルダー"変数を取り除くのは大きな仕事のようです。

答えて

2

CompletableFutureの直鎖を持つ必要はありません。実際には、すでにタイムアウトを実装するためにかなり複雑なcreateTimeoutFuture(DURATION)が原因ではありません。あなたは、単にそれをこのように置くことができます。

public CompletableFuture<ExecutionContext> createFuture() { 
    CompletableFuture<Process> proc=CompletableFuture.supplyAsync(
     () -> { 
      try { 
       return new ProcessBuilder(COMMAND).redirectErrorStream(true).start(); 
      } catch (IOException e) { 
       throw new UncheckedIOException(e); 
      } 
     }, SCHEDULER); 
    CompletableFuture<ExecutionContext> result 
     =proc.thenApplyAsync(process -> PARSER.parse(process.getInputStream()), SCHEDULER); 
    proc.thenAcceptAsync(process -> { 
     if(!process.waitFor(DURATION, TimeUnit.WHATEVER_DURATION_REFERS_TO)) { 
      process.destroyForcibly(); 
      result.completeExceptionally(
       new DatasourceTimeoutException(new TimeoutException())); 
     } 
    }); 
    return result; 
} 

あなたがTIMOUT未来を維持したい場合は、おそらくあなたが重要であると、プロセスの起動時間を考慮して、あなたは

public CompletableFuture<ExecutionContext> createFuture() { 
    CompletableFuture<Throwable> timeout=createTimeoutFuture(DURATION); 
    CompletableFuture<Process> proc=CompletableFuture.supplyAsync(
     () -> { 
      try { 
       return new ProcessBuilder(COMMAND).redirectErrorStream(true).start(); 
      } catch (IOException e) { 
       throw new UncheckedIOException(e); 
      } 
     }, SCHEDULER); 
    CompletableFuture<ExecutionContext> result 
     =proc.thenApplyAsync(process -> PARSER.parse(process.getInputStream()), SCHEDULER); 
    timeout.exceptionally(t -> new DatasourceTimeoutException(t)) 
      .thenAcceptBoth(proc, (x, process) -> { 
       if(process.isAlive()) { 
        process.destroyForcibly(); 
        result.completeExceptionally(x); 
       } 
      }); 
    return result; 
} 
+0

'.waitFor'ブロックと私はおそらく非常に大きな' InputStream'を消費したいので、私は使うことができません。(したがって、 '.redirectErrorStream(true)'、後で "エラー検出"があります。 2番目の方法はちょっと複雑です( 'CompletableFuture 'を含む3つの先物)、私は試してみましょう。 – Xaerxess

+1

*非同期*動作でブロックします。それは 'thenAcceptAsync'やよく' CompleteableFuture'の一般的な段階です。独立したステージを同時に実行できます。ここで、 'PARSER.parse'と' process.waitFor'は同時に独立した段階で実行されます。 – Holger

+0

ああ、そうだ。 waitForを試してみましょう! – Xaerxess

1

を使用することができます私が使用しましたJavaで適切なクロージャとなるものをエミュレートするための1つのアイテム配列。

フィールドを持つプライベート静的クラスを使用する別のオプションもあります。メリットは、目的をより明確にし、大きなクロージャを持つガベージコレクタに少しだけ影響を与えます。つまり、N個のフィールドとN個の長さの配列を持つオブジェクトです。同じフィールドを閉じる必要がある場合に便利です他の方法で。

これは、CompletableFutureの範囲外であっても、事実上パターンであり、ラムダがJavaのものであったのはずっと前に(ab)使用されていました。匿名のクラス。だから、それほど気分を悪くしないでください。Javaの進化が私たちに適切な閉鎖を提供していないということだけです(まだですか?)。

.handle()内の値をCompletableFutureから戻すことができるので、完了結果を完全にラップしてラッパーを返すことができます。私の意見では、これは手動クロージャより優れているわけではなく、将来、そのようなラッパーを作成するという事実を追加しました。

サブクラス化CompletableFutureは不要です。その動作を変更することには興味がありません。データを添付するだけで、現在のJavaの最終的な変数キャプチャで行うことができます。つまり、プロファイルを作成し、これらのクロージャを作成すると実際にはパフォーマンスに何らかの影響を与えていることがわかりますが、これは疑いの余地がありません。

関連する問題