23

私は最近、スレッドセーフがほとんどない大きなJavaアプリケーションを継承しました。私が現在取り組んでいるのは、非常に悪いを使用する代わりに、すべてのスレッドが中断を正しく処理できるようにすることThread.stop()です。

問題の一部は、割り込みフラグをクリアするすべてのメソッド呼び出しがわからないことです。

現在、次のことが割り込みフラグをクリアすることを知っています。

Thread.interrupted()
Thread.sleep(long)
Thread.join()
Thread.join(long)
Object.wait()
Object.wait(long)

他に何が欠けていますか?ありがとうございました

4

3 に答える 3

49

問題の一部は、割り込みフラグをクリアするすべてのメソッド呼び出しがわからないことです。

次のメソッドは、呼び出すだけで割り込みフラグをクリアすることを明確にすることが重要です。

Thread.interrupted()
Thread.isInterrupted(true) -- added to your list

このため、Thread.currentThread().isInterrupted()代わりに常に使用する必要があります。

次のメソッドは、呼び出されてからスレッドが中断された場合、またはスレッドがすでに中断されてから呼び出された場合にすぐにスローすることで、中断されたフラグをクリアします(以下のjunitコードを参照)。したがって、フラグをクリアするのはメソッドではなく、例外をスローすることでクリアされます。InterruptedException

あなたの最初のリスト:

Thread.interrupted()
Thread.sleep(long)
Thread.join()
Thread.join(long)
Object.wait()
Object.wait(long)

リストに追加:

Thread.sleep(long, int)
Thread.join(int, long)
Thread.isInterrupted(true)
Object.wait(int, long)
BlockingQueue.put(...)
BlockingQueue.offer(...)
BlockingQueue.take(...)
BlockingQueue.poll(...)
Future.get(...)
Process.waitFor()
ExecutorService.invokeAll(...)
ExecutorService.invokeAny(...)
ExecutorService.awaitTermination(...)
CompletionService.poll(...)
CompletionService.take(...)
CountDownLatch.await(...)
CyclicBarrier.await(...)
Semaphore.acquire(...)
Semaphore.tryAcquire(...)
Lock.lockInteruptibly()
Lock.tryLock(...)

キャッチするコードの適切なパターンはInterruptedException、スレッドをすぐに再中断​​することであることに注意してください。thread.isInterrupted()他の人がこの方法に依存している場合に備えて、これを行います。

try {
    ...
} catch (InterruptedException e) {
    // immediately re-interrupt the thread
    Thread.currentThread().interrupt();
    // log the exception or [likely] quit the thread
}

これのいくつかを示すJUnitコード:

assertFalse(Thread.currentThread().isInterrupted());
// you can do this from another thread by saying: someThread.interrupt();
Thread.currentThread().interrupt();
// this method does _not_ clear the interrupt flag
assertTrue(Thread.currentThread().isInterrupted());
// but this one _does_ and should probably not be used
assertTrue(Thread.interrupted());
assertFalse(Thread.currentThread().isInterrupted());
Thread.currentThread().interrupt();
assertTrue(Thread.currentThread().isInterrupted());
try {
    // this throws immediately because the thread is _already_ interrupted
    Thread.sleep(1);
    fail("will never get here");
} catch (InterruptedException e) {
    // and when the InterruptedException is throw, it clears the interrupt
    assertFalse(Thread.currentThread().isInterrupted());
    // we should re-interrupt the thread so other code can use interrupt status
    Thread.currentThread().interrupt();
}
assertTrue(Thread.currentThread().isInterrupted());
于 2012-09-09T13:30:02.457 に答える
16

InterruptedException一般的な規則は次のとおりです。 (+ )をスローするメソッドはThread.interrupted()、割り込みフラグをクリアします。

InterruptedExceptionしたがって、スレッドを割り込み可能にするためには、スレッドを巻き戻したり、割り込みフラグを復元したりせずに、キャッチされたすべての場所を見つける必要があります。チェックされた例外なのでInterruptedException、実行するのは難しくありません。

于 2012-05-01T18:04:09.167 に答える
3

これが超楽しい例です:

バージョン1.1.4より前のch.qos.logback.core.AsyncAppenderBaseは、スレッドのフラグをリセットせずに、InterruptedExceptionをキャッチして飲み込みます。

したがって、このロガーにルーティングするもの(slf4jなど)を使用すると、スレッドの割り込みステータスがサイレントに消費されます。「Cos、つまり、すべての可能なログ操作の前後にスレッド割り込みステータスをチェックしないのは誰ですか?

于 2016-05-13T10:06:45.920 に答える