スタックして永久に実行し続ける可能性のあるスレッドがあります。したがって、一定の時間が経過したら、実行を停止し、finally メソッドに移動してクリーンアップを行ってから終了したいと考えています。これを安全に行うにはどうすればよいですか?ありがとう。
これを行う方法について最初に考えたのは、子スレッドを作成し、それをスリープさせてからクリーンアップを行うことでした。しかし、親スレッドがまだ実行しようとしていて実行できない場合は、エラーが出力されます。
スタックして永久に実行し続ける可能性のあるスレッドがあります。したがって、一定の時間が経過したら、実行を停止し、finally メソッドに移動してクリーンアップを行ってから終了したいと考えています。これを安全に行うにはどうすればよいですか?ありがとう。
これを行う方法について最初に考えたのは、子スレッドを作成し、それをスリープさせてからクリーンアップを行うことでした。しかし、親スレッドがまだ実行しようとしていて実行できない場合は、エラーが出力されます。
提案 1: コードを try ブロックに配置し、wait() ステートメントを使用すると、interruptedException をキャッチして、finally に続くことができます。別のスレッドが notify() または notifyAll() を送信して、スレッドを中断する必要がある場合に割り込みを発生させる必要があります。
提案 2: 私は Java の初心者にすぎませんが、スレッドが動かなくなったということは、try/finally ブロック内でカスタム例外をスローできる必要があることを意味します。
(1)
最善の解決策は、タイムアウトでデータを送信することです。次のように見えるはずです
try {
mySendingDataLibraryApi.sendData(data, timeout /*, timeUnit */);
// some new APIs enable also to configure the time unit of the required timeout.
// Older APIs typically just use milliseconds.
} catch (TimeoutException e) {
doCleanup(); // your cleanup method.
}
(2)
使用している API がそのような構成を公開していないためにこれが適用できない場合、2 番目に良い解決策は、割り込み可能な APIsendData
メソッドを使用して、実行中のスレッドを中断することです。これは、そのような中断可能な API が提供されているという事実に依存しています。時限メソッドが API によって提供されていない場合、そのようなメソッドの存在はあまり期待できません...とにかく、タスクを実行するスレッド内のコードは次のようになります。
class MySendingDataRunnable implements Runnable {
@Override
public void run() {
try {
mySendingDataLibraryApi.sendDataInterruptibly(data);
} catch (InterruptedException e) {
doCleanup(); // your cleanup method.
// here either re-throw InterruptedExecption
// or restore the interrupted state with Thread.currentThread().interrupt();
}
}
}
スレッドの呼び出し元のコードは、ExecutorServiceとそのメソッドによって返されるFutureインスタンスを使用しFuture<?> submit(Runnable task)
て、目的の時間待機し、mayInterruptIfRunning
引数を に設定してタスクをキャンセルする必要がありtrue
ます。
final ExecutorService executor = Executors.newSingleThreadExecutor();
final Future<?> future = executor.submit(new MySendingDataRunnable());
try {
final Object noResult = future.get(60, TimeUnit.SECONDS); // no result for Runnable
} catch (InterruptedException e) {
// here again either re-throw or restore interupted state
} catch (ExecutionException e) {
// some applicative exception has occurred and should be handled
} catch (TimeoutException e) {
future.cancel(true); // *** here you actually cancel the task after time is out
}
(3)
使用する API がこれらの機能 (時限/割り込み可能メソッド) のいずれも提供しない場合は、創造性を発揮する必要があります。この 1 行のブロック コードは、何らかのリソースでブロックされている必要があります。このリソースに手を差し伸べて、シャットダウンするか切断して、暗黙的にタスクを終了させます。典型的な例は、ネットワーク接続を閉じることです。
注:上記の解決策は、実際にタスクをキャンセルし、スレッドを解放して以降のタスクを実行する方法を提供するだけです。スレッドはまだ生きているかもしれません。通常、スレッドの強制終了は、タスクが完了した (または失敗した) ときに行うことではありません。二度と実行されないはずの特定のタスク用のスレッドを作成した場合は、問題ありません。そのような場合、上記を使用してそのメソッドExecutorService
を呼び出します。そして、最善の努力をするだけであり、通常、実際のタスクが中断可能であるかどうかに依存します...shutdownNow()
shutdownNow()
ここに詳細な記事があります(やや古いですが、それでもなお)。
ブロッキング コールのタイムアウトを設定する必要があります。タイムアウトがない場合は、呼び出しを抽象化し、そのようにタイムアウトします。
タスクの完了ステータスをポーリングする 1 つのスレッドを作成し、ある値を超えた場合はそれを強制終了できます。タスク自体には、さらに別のスレッドが必要です。価値のあるタスクを作成することでこれを行いstaleness
ます。すべてのタスクを定期的にポーリングし、古い場合はキャンセルします。