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

Java 스레드의 중지 메커니즘에 대한 간단한 분석

스레드 중지 메커니즘은 스레드를 블록된 대기 상태에서 깨우고, 목표 스레드의 현재 처리 프로세스를 중지하고 새 명령에 응답하려는 방법을 제공합니다. Java는 개발자에게 이 자유를 주었으므로 적절히 사용해야 합니다.
오늘은 Java 스레드의 중지 메커니즘에 대해 이야기해 보겠습니다.

스레드 중지 메커니즘은 두 가지 일반적인 용도를 제공합니다:

스레드를 블록된 대기 상태에서 깨우고 적절한 "제어된 중지" 처리를 수행합니다.
목표 스레드에 알림을 전달하려고 시도합니다: 현재 처리 프로세스를 중지하고 새 명령에 응답하십시오.
첫 번째 용도로 예를 들어, 다음 코드를 보세요:

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

이 코드는 Java가 제공하는 wait를 사용합니다/notify 메커니즘, 스레드가 lock.wait()을 수행할 때는 블록됩니다. 스레드가 다시 실행되는 세 가지 상황이 있습니다.

1시간 초과 1000ms 완료, 정상적으로 다음 코드를 실행합니다.

2또 다른 스레드가 다음 코드를 실행하여 적극적으로 깨우기

synchronized (lock) {
  lock.notifyAll(); // 또는 lock.notify();
}

이는 정상적으로 다음 코드를 실행합니다.

3또 다른 스레드가 대기 중인 스레드를 "중지"하려고 요청합니다

// 대기 중인 스레드의 참조를 얻습니다
Thread a;
a.interrupt();

락.wait()에서 InterruptedException 예외가 발생하는 "중지"된 스레드 a가 있습니다.

따라서 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를 throw합니다.

// 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#w로 이메일을 보내 주시기 바랍니다.3codebox.com(보내는 이메일에서 #을 @으로 변경하시오)를 통해 신고하시고 관련 증거를 제공하시면, 실제로 확인되면 이 사이트는 즉시 저작권 침해 내용을 삭제할 것입니다。

추천 항목