中断された可能性のある状態を維持しながら、結果が切断されたブロッキング メソッドを処理するさまざまな方法を試してきました。送信と受信を調整するのが難しい、異種のクラスとメソッドを処理しなければならないことにイライラすることがわかりました。
次の例では、SomeBlockingMethod()
通常void
、メッセージが他のプロセスに送信されると戻ります。しかし、代わりにsynchronized
、結果を受け取るリスナーで作成しました。スレッドにスピンオフするwait()
ことで、タイムアウトまたは無期限で結果を得ることができます。
結果が返されると、スレッド化されたタスクの結果を待っている間に一時停止しなければならなかった特定の状態で作業を続けることができるので、これは素晴らしいことです。
これは私のアプローチに何か問題がありますか?
この質問は一般的なように思えるかもしれませんが、 Javaでのスレッド化に関するアドバイスを特に探しています。
疑似コードの例:
public class SomeClass implements Command {
@Override
public void onCommand() {
Object stateObject = new SomeObjectWithState();
// Do things with stateObject
Runnable rasync = () -> {
Object r = SomeBlockingMethod();
// Blocking method timed out
if (r == null)
return;
Runnable rsync = () -> {
// Continue operation on r which must be done synchronously
// Also do things with stateObject
};
Scheduler().run(rsync);
};
Scheduler().run(rasync);
}
CompletableFuture で更新:
CompletableFuture<Object> f = CompletableFuture.supplyAsync(() -> {
return SomeBlockingMethod();
});
f.thenRun(() -> { () -> {
String r = null;
try {
r = f.get();
}
catch (Exception e) {
e.printStackTrace();
}
// Continue but done asynchronously
});
またはさらに良い:
CompletableFuture.supplyAsync(() -> {
return SomeBlockingMethod();
}).thenAccept((
Object r) -> {
// Continue but done asynchronously
});
厳密に使用する場合の問題CompletableFuture
は、それCompletableFuture.thenAccept
がグローバル スレッド プールから実行され、呼び出しスレッドとの同期が保証されないことです。
同期タスクにスケジューラを追加すると、これが修正されます。
CompletableFuture.supplyAsync(() -> {
return SomeBlockingMethod();
}).thenAccept((
Object r) -> {
Runnable rsync = () -> {
// Continue operation on r which must be done synchronously
};
Scheduler().run(rsync);
});
完全なスケジューラ メソッドと比較して使用する場合の注意点は、CompletableFuture
外部に存在する以前の状態は最終的または実質的に最終的でなければならないということです。