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

Análise superficial do mecanismo de interrupção de threads em Java

The thread interruption mechanism provides a method to wake up a thread from a blocked waiting state, attempt to interrupt the existing processing flow of the target thread, and make it respond to a new command. Java leaves this freedom to developers, and we should make good use of it.
Today, let's talk about the interruption mechanism of Java threads.

The thread interruption mechanism provides a method, with two common uses:

Wake up the thread from the blocked waiting state and perform the corresponding 'controlled interruption' handling.
Attempt to inform the target thread: please interrupt the current processing flow and respond to a new command.
For example, let's look at the following code for the first use case:

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

This code uses the wait provided by Java/The notify mechanism, when a thread executes lock.wait(), will block, and there are three situations that cause the thread to resume running.

1timeout 1000ms ends, executing the next line of code normally.

2and another thread executes the following code to wake up actively

synchronized (lock) {
  lock.notifyAll(); // or lock.notify();
}

This will also execute the next line of code normally.

3and another thread requests to 'interrupt' the waiting thread

// Get the reference of the waiting thread
Thread a;
a.interrupt();

A thread 'a' interrupted, will throw an InterruptedException at lock.wait().

Portanto, você pode considerar que o object.wait() internamente está fazendo essas coisas: }}

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--;
  }
}

Isso não é completamente correto, porque wait não usa esse método de 'busca ativa' para verificar, mas a lógica de julgamento do sinal de interrupção é correta.

Vamos explorar a partir da operação mencionada anteriormente de 'interrupção manual'

// 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();
}
// Apenas para configurar o sinal de interrupção
private native void interrupt0();

Pode-se ver que thread.interrupt() primeiro verifica a permissão, então chama realmente interrupt0() para configurar o sinal de interrupção da thread, e se a thread atual tiver o Interruptible do nio, também será chamado de volta.

Atenção, interrupt0() apenas configura o sinal de interrupção da thread.

Quando uma thread não está bloqueada, não está em áreas como object.wait(), thread.join(), Thread.sleep() que não são controladas pela lógica do programa Java, o que acontece? A resposta é que não acontece nada, se a thread foi interrompida, isso só pode ser conhecido através de uma verificação ativa do sinal de interrupção.

Como verificar? Thread expõe dois métodos, Thread.interrupted() e 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);

Pode-se ver que ambos dependem internamente do isInterrupted(boolean), que retorna se a thread foi interrompida e, conforme necessário, limpa o sinal de interrupção.

Quando uma chamada de função pode causar bloqueio, as funções da biblioteca Java marcam a assinatura de bloqueio com throws InterruptedException e exigem que se escreva um try catch para lidar com a interrupção.

Quando uma thread se bloqueia, conforme descrito acima, o Java verifica o sinal de interrupção, o limpa e então lança InterruptedException.

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

Se uma thread receber InterruptedException e, após isso, executar código que causaria bloqueio, ela continuará a bloquear como se nada tivesse acontecido. Isso porque o Java limpa o sinal de interrupção internamente!

Normalmente, escrevemos os seguintes três tipos de código para lidar com InterruptedException:

Delega InterruptedException para o nível superior de tratamento.

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

Reconfigure o sinal de interrupção ao encontrar InterruptedException.

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

Conclua as tarefas antes de rethrower 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;
  }
}

Se uma thread ignorar o sinal de interrupção e InterruptedException, ela ainda pode funcionar bem. No entanto, isso vai contra o propósito original de projetar multi-threading, onde esperamos que as threads funcionem de forma harmônica e colaborativa para alcançar funções específicas. Portanto, a thread controlada deve responder ao sinal de interrupção. Java oferece essa liberdade aos desenvolvedores, e devemos usá-la bem.

Isso é tudo sobre o mecanismo de interrupção das threads Java que apresentamos a você esta vez. Se ainda houver algo que você não entenda, você pode discutir na área de comentários abaixo. Agradecemos o apoio ao Tutorial de Grito.

Declaração: O conteúdo deste artigo é de origem na Internet, pertencente ao autor original. O conteúdo é contribuído e carregado voluntariamente pelos usuários da Internet, este site não possui direitos de propriedade, não foi editado manualmente e não assume responsabilidades legais relacionadas. Se você encontrar conteúdo suspeito de violação de direitos autorais, por favor, envie um e-mail para: notice#oldtoolbag.com (ao enviar e-mail, substitua # por @ para denunciar e forneça provas relevantes. Apenas se confirmado, o site deletará imediatamente o conteúdo suspeito de violação de direitos autorais.)

Você também pode gostar