Um encadeamento pode estar nos quatro estados a seguir:
1: Novo (novo): quando o encadeamento é criado, ele permanecerá neste estado por um curto período de tempo. Nesse ponto, ele alocou os recursos de sistema necessários e executou a inicialização. Neste momento, a thread já está qualificada para o tempo de CPU, e então o agendador irá transformar esta thread em um estado executável ou bloqueado.
2: Pronto (Executável): Neste estado, enquanto o agendador alocar fatias de tempo para threads, as threads podem ser executadas. Em outras palavras, a qualquer momento, o tópico pode ou não ser executado. Desde que o planejador possa alocar fatias de tempo para threads, ele pode ser executado, o que é diferente dos estados morto e bloqueado.
3: Bloqueado: o thread pode ser executado, mas alguma condição o impede de ser executado. Quando um thread está em um estado bloqueado, o agendador irá ignorar o thread e não alocará nenhum tempo de CPU para o thread. Não será possível realizar operações até que o thread entre novamente no estado pronto.
4: Dead (Dead): O encadeamento no estado morto ou encerrado será escalonável quando terminar, e não obterá tempo de CPU, sua tarefa terminou ou não pode mais ser executada, da maneira usual quando a tarefa termina Retorne do método run (), mas o thread da tarefa ainda pode ser interrompido, como você verá.
A entrada no estado de bloqueio pode ter os seguintes motivos:
1: dormir dormir.
2: Suspenda o thread chamando wait (). Até que o encadeamento obtenha notificar () ou notificarAll ().
3: A tarefa está aguardando a conclusão de uma entrada / saída.
4: A tarefa tenta usar outros métodos de controle de sincronização em um objeto, mas o bloqueio do objeto não está disponível porque outra tarefa já adquiriu o bloqueio.
Ao interromper uma tarefa bloqueada, pode ser necessário limpar os recursos. Por causa disso, a interrupção no meio do método run () da tarefa é mais como uma exceção lançada, portanto, exceções são usadas neste tipo de interrupção de exceção em threads java. Portanto, você precisa escrever cuidadosamente as cláusulas try-catch para limpar tudo de maneira adequada.
A classe Thread contém o método Interrupt () , para que você possa interromper a tarefa bloqueada.Este método definirá o status de interrupção do thread. Se um thread estiver bloqueado ou tentando realizar uma operação de bloqueio, chamar este método neste momento lançará uma InterruptedException .
Quando a exceção é lançada ou a tarefa chama o método Thread.interrupt, o status de interrupção é redefinido.
O método Thread.interrupt () fornece uma segunda maneira de sair de run () sem lançar uma exceção. Para chamar Thread.interrupt (), você precisa manter um objeto Thread.
O Executor fornecido pela nova biblioteca de classes atual parece evitar a manipulação direta de objetos Thread.
Se shutdownNow () for chamado no Executor , ele enviará uma chamada interrupt () para todos os threads que iniciar .
Cancelar (booleano) é uma forma de interromper uma única thread iniciada pelo Executor. Neste momento, a tarefa deve ser iniciada pelo método submit () em vez do método execute () .
O método submit () retornará um Future <?> Genérico, no qual o método cancel (booleano) (o parâmetro é verdadeiro) pode ser chamado para encerrar a tarefa .
class SleepBlocked implements Runnable{
public void run() {
try {
TimeUnit.MILLISECONDS.sleep(100);
}catch(InterruptedException e) {
System.out.println("InterruptedException");
}
System.out.println("Exiting SleepBlocked.run()");
}
}
class IOBlocked implements Runnable{
private InputStream in;
public IOBlocked(InputStream is) {
in=is;}
@Override
public void run() {
try {
System.out.println("Waiting for read():");
in.read();
}catch(IOException e) {
if(Thread.currentThread().isInterrupted()) {
System.out.println("Interrupted from blocked I/O");
}
else {
throw new RuntimeException(e);
}
}
System.out.println("Exiting IOBlocked.run()");
}
}
class SynchronizedBlocked implements Runnable{
public synchronized void f() {
while(true) {
Thread.yield();
}
}
public SynchronizedBlocked() {
new Thread() {
public void run() {
f();
}
}.start();
}
public void run() {
System.out.println("Trying to call f()");
f();
System.out.println("Exiting SynchronizedBlocked.run()");
}
}
public class Interrupting {
private static ExecutorService exec=Executors.newCachedThreadPool();
static void test(Runnable r) throws InterruptedException{
Future<?> f=exec.submit(r);
TimeUnit.MILLISECONDS.sleep(100);
System.out.println("Interrupting "+r.getClass().getName());
f.cancel(true);
System.out.println("Interrupting sent to "+r.getClass().getName());
}
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
test(new SleepBlocked());
test(new IOBlocked(System.in));
test(new SynchronizedBlocked());
TimeUnit.MILLISECONDS.sleep(3);
System.out.println("Absorbing with System.exit(0)");
System.exit(0);
}
}
/*
Exiting SleepBlocked.run()
Interrupting demo.SleepBlocked
Interrupting sent to demo.SleepBlocked
Waiting for read():
Interrupting demo.IOBlocked
Interrupting sent to demo.IOBlocked
Trying to call f()
Interrupting demo.synchronizedBlocked
Interrupting sent to demo.synchronizedBlocked
Absorbing with System.exit(0)
*/
Cada tarefa do programa acima representa um tipo diferente de bloqueio. SleepBlock () é um exemplo de bloqueio interrompível, enquanto IOBlocked e SynchronizedBlocked são exemplos de bloqueio não bloqueado. Portanto, I / O e espera no bloco sincronizado são ininterruptos. Navegar no código pode descobrir que não importa se é I / O ou tentando chamar o método sincronizado, nenhum manipulador InterruptedException é necessário.
Em SynchronizedBlocked, devemos primeiro adquirir o bloqueio, que é obtido criando uma instância da classe Thread anônima, que chama f () para adquirir o bloqueio do objeto primeiro. Como o método f () é um loop infinito e nunca retorna, o bloqueio nunca será liberado. Neste momento, o método Synchronized.run () está tentando adquirir o bloqueio do objeto e bloqueia aguardando a liberação do bloqueio.
Pode-se ver no exemplo de programa acima que você não pode interromper uma thread que está tentando adquirir um bloqueio sincronizado ou tentando realizar uma operação de E / S.
Método de processamento de I / O para este
Quanto à classe nio de I / O de interrupção mais amigável ao usuário, nós a adicionaremos quando terminarmos de aprender.
class BlockedMutex{
private Lock lock=new ReentrantLock();
public BlockedMutex() {
lock.lock();
}
public void f() {
try {
lock.lockInterruptibly();
System.out.println("lock acquired in f()");
}catch(InterruptedException e) {
System.out.println("Interruppted from lock acquisition in f()");
}
}
}
class Blocked2 implements Runnable{
BlockedMutex blocked=new BlockedMutex();
public void run() {
System.out.println("Waiting for f() in BlockedMutex");
blocked.f();
System.out.println("Broken out of blocked call");
}
}
public class Interrupting2 {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
Thread t=new Thread(new Blocked2());
t.start();
TimeUnit.MILLISECONDS.sleep(1);
System.out.println("Issuing t.interrupt()");
t.interrupt();
}
}
O programa acima: java SE5 adiciona um recurso que permite que as tarefas bloqueadas no ReentrantLock sejam interrompidas, o que é diferente das tarefas bloqueadas em métodos sincronizados ou seções críticas.