English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Javaのスレッドの中断メカニズムの簡単な分析

スレッド中断メカニズムは、スレッドをブロック状態から唤醒し、ターゲットスレッドの現在の処理プロセスを中断して新しいコマンドに対応させる方法を提供します。Javaは開発者にこの自由を提供していますが、それを適切に使用すべきです。
今日はJavaのスレッド中断メカニズムについて話しましょう。

スレッド中断メカニズムは、スレッドをブロック状態から唤醒し、ターゲットスレッドの現在の処理プロセスを中断して新しいコマンドに対応させる方法を提供します。Javaは開発者にこの自由を提供していますが、それを適切に使用すべきです。

スレッドをブロック状態から唤醒し、対応する「制御中断」処理を行います。
ターゲットスレッドに通知:現在の処理プロセスを中断し、新しいコマンドに対応してください。
第1つの用途として、以下のコードをご覧ください:

synchronized (lock) {
  try {
    while (!check()) {
      lock.wait(1000);
    }
  }
    e.printStackTrace();
  }
}

このコードはJavaが提供するwaitを使用しています。/notifyメカニズムでは、スレッドがlock.wait()を実行するとブロックされ、スレッドが再開される3つの状況があります。

1、タイムアウト 1000msで終了し、通常通り次の一行のコードを実行します。

2、別のスレッドが以下のコードを実行して自動的に唤醒します

synchronized (lock) {
  lock.notifyAll(); // またはlock.notify();
}

これは通常通り次の一行のコードを実行します。

3、別のスレッドが待機中のスレッドを「中断」を要求

// 待機中のスレッドの参照を取得
Thread a;
a.interrupt();

「中断」されたスレッドaは、lock.wait()でInterruptedException例外をスローします。

したがって、object.wait() 内部では以下のようなことが行われています:

boolean checkTimeout = timeout > 0;
Thread current = Thread.currentThread();
lock.addWaiter(current);
while (!current.isNotified()) {
  if (current.isInterrupted()) {
    current.clearInterrupted();
    throw new InterruptedException();
  }
  if (checkTimeout) {
    if (timeout == 0) break;
    timeout--;
  }
}

これは完全に正確ではありません。なぜなら wait はこの「忙しい待機」方式を使用してチェックを行わないためです。しかし、フラグの判断ロジックは正しいです。

以下では、上記で述べた「手動で中断を発生させる」操作から探求を始めましょう

// sun.nio.ch.Interruptible
public interface Interruptible {
  void interrupt(Thread var1);
}
// java.lang.Thread
private volatile Interruptible blocker;
private final Object blockerLock = new Object();
public void interrupt() {
  if (this != Thread.currentThread())
    checkAccess();
  synchronized (blockerLock) {
    Interruptible b = blocker;
    if (b != null) {
      interrupt0();
      b.interrupt(this);
      return;
    }
  }
  interrupt0();
}
// ただ中断フラグを設定するため
private native void interrupt0();

thread.interrupt() はまず権限を判断し、その後 interrupt0() を実行してスレッドの中断フラグを設定します。さらに、現在のスレッドが nioのInterruptibleを持っている場合、それにコールバックも行います。

注意,interrupt0() は単にスレッドの中断フラグを設定しています。

スレッドがブロックされていない場合、object.wait()、thread.join()、Thread.sleep() などの Java プログラムの論理から制御されない領域にない場合、何が起こるか?答えは何も起こらないことです。スレッドが割り込みされているかどうかは、中断フラグを検査することでわかります。

どのようにチェックしますか?Thread は Thread.interrupted() と thread.isInterrupted() の二つのインターフェースを提供しています。

// java.lang.Thread
public static boolean interrupted() {
  return currentThread().isInterrupted(true);
}
public boolean isInterrupted() {
  return isInterrupted(false);
}
private native boolean isInterrupted(boolean clearInterrupted);

両方とも内部の isInterrupted(boolean) に依存しており、それはスレッドが割り込みされているかどうかを返し、必要に応じて中断フラグをクリアします。

関数の呼び出しがブロックされる場合、Java ライブラリ関数はブロックの元のシグネチャに throws InterruptedException をマークし、中断の処理を try catch で書くことを要求します。

スレッドがブロックされた場合、上記のように、Java は中断フラグをチェックし、それをクリアしてから InterruptedException をスローします。

// java.lang.Object
public final void wait() throws InterruptedException {
  wait(0);
}
public final native void wait(long timeout) throws InterruptedException;

スレッドが InterruptedException を受け取った後で、ブロックされるコードをまだ実行した場合、それが「何も起こらないように」ブロックし続けます。なぜなら、Java は内部で中断フラグをクリアしているからです!

InterruptedException を処理するためによく使われるコードの三種類があります:

InterruptedException を上位層で処理します。

public void foo() throws InterruptedException {
  synchronized (lock) {
    lock.wait();
  }
}

InterruptedExceptionが発生した場合は、中断フラグをリセットします。

try {
  synchronized (lock) { 
    lock.wait(); 
  } 
} 
  Thread.currentThread().interrupt();
  //break; 
}

まず他の作業を終わらせ、InterruptedExceptionを再投げます。

public void bar() throws InterruptedException {
  InterruptedException ie = null;
  boolean done = false;
  while (!done) {
    synchronized (lock) {
      try {
        lock.wait();
      }
        ie = e;
        continue;
      }
    }
    done = true;
  }
  if (ie != null) {
    throw ie;
  }
}

スレッドが中断フラグとInterruptedExceptionを無視しても、それでもうまく動作することができます。しかし、私たちが多スレッドを設計した本質とは異なります。私たちは特定の機能を実現するためにスレッド間で協調して和谐に作業するように設計したいです。したがって、制御されたスレッドは中断に対応する必要があります。Javaは開発者にこの自由を提供していますが、私たちはそれを適切に利用すべきです。

これで今回ご紹介したJavaスレッドの中断メカニズムに関する全ての内容が終わりました。何か不明な点があれば、下のコメント欄で議論してください。呐喊チュートリアルへのサポートを感謝します。

声明:この記事の内容はインターネットから収集され、著作権者に帰属します。インターネットユーザーが自発的に貢献し、アップロードした内容であり、このサイトは所有権を持ちません。また、人工編集は行われていません。著作権侵害の疑いがある場合は、以下のメールアドレスにご連絡ください:notice#oldtoolbag.com(メールを送信する際には、#を@に変更してください)で通報し、関連する証拠を提供してください。一旦確認が取れたら、このサイトは即座に侵害された内容を削除します。

基礎教程
おすすめ