Thread é a unidade básica de operação do sistema operacional. Ele é encapsulado em um processo. Mesmo que não criemos um thread manualmente, o processo terá um thread padrão em execução.
Para a JVM, quando escrevemos um programa de thread único para execução, há pelo menos dois threads em execução na JVM, um é o programa que criamos e o outro é a coleta de lixo.
Informações básicas do tópico
Podemos obter algumas informações sobre o thread atual através do método Thread.currentThread() e modificá-lo.
Vejamos o seguinte código:
Thread.currentThread().setName("Teste");
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
nome = Thread.currentThread().getName();
prioridade = Thread.currentThread().getPriority();
nomeGrupo = Thread.currentThread().getThreadGroup().getName();
isDaemon = Thread.currentThread().isDaemon();
System.out.println("Nome do Tópico:" + nome);
System.out.println("Prioridade:" + prioridade);
GroupName , cada thread estará em um grupo de threads por padrão. Também podemos criar explicitamente um grupo de threads. Um grupo de threads também pode conter grupos de subthreads, de modo que threads e grupos de threads formem uma estrutura em árvore.
Name , cada thread terá um nome. Se não for especificado explicitamente, a regra de nome será "Thread-xxx".
Priority , cada thread terá sua própria prioridade, e a forma de tratamento da prioridade da JVM é "preemptiva". Quando a JVM encontra um thread com alta prioridade, ela imediatamente executa o thread para vários threads com prioridades iguais, a JVM os pesquisa. A prioridade do thread Java varia de 1 a 10, sendo o padrão 5. A classe Thread define duas constantes: MIN_PRIORITY e MAX_PRIORITY para representar as prioridades mais altas e mais baixas.
Podemos observar o código a seguir, que define dois threads com prioridades diferentes:
Tópico thread2 = novo Tópico("alto")
{
execução de vazio público ()
{
para (int i = 0; i < 5; i++)
{
System.out.println("Thread 2 está em execução.");
}
}
};
thread1.setPriority(Thread.MIN_PRIORITY);
thread2.setPriority(Thread.MAX_PRIORITY);
thread1.start();
thread2.start();
}
thread1.start();
}
Como criar um tópico
Todo o conteúdo acima demonstra algumas informações no tópico padrão, então como criar um tópico? Em Java, temos 3 maneiras de criar threads.
Threads em Java herdam a classe Thread ou implementam a interface Runnable. Vamos examiná-los um por um.
Use classes internas para criar threads
Podemos usar classes internas para criar threads. O processo consiste em declarar uma variável do tipo Thread e substituir o método run. O código de exemplo é o seguinte:
Podemos derivar uma classe de Thread e substituir seu método run de maneira semelhante à anterior. O código de exemplo é o seguinte:
public static void createThreadBySubClass()
{
thread MyThread = new MyThread();
thread.start();
}
Podemos definir uma classe para implementar a interface Runnable e então usar uma instância dessa classe como parâmetro para construir o construtor da variável Thread. O código de exemplo é o seguinte:
public static void createThreadByRunnable()
{
MyRunnable executável = new MyRunnable();
Thread thread = new Thread(executável);
thread.start();
}
Isso envolve o modo de execução de multithreading em Java. Para Java, quando o multithreading está em execução, há diferenças entre "multithreading de vários objetos" e "multithreading de objeto único":
Multithreading de vários objetos , o programa cria vários objetos de thread durante a execução e um thread é executado em cada objeto.
Multithreading de objeto único , o programa cria um objeto de thread durante a execução e executa vários threads nele.
Obviamente, do ponto de vista de sincronização e agendamento de threads, o multithreading de vários objetos é mais simples. Dos três métodos de criação de thread acima, os dois primeiros são "multi-objeto multi-thread" e o terceiro pode usar "multi-objeto multi-thread" ou "single-object single-thread".
Vejamos o código de exemplo a seguir, que usará o método Object.notify. Este método ativará um thread no objeto e o método Object.notifyAll ativará todos os threads no objeto.
public static void main(String[] args) lança InterruptedException
{
notificarTeste();
notificarTeste2();
notificarTeste3();
}
private static void notifyTest() lança InterruptedException
{
MeuThread[] arrThreads = new MeuThread[3];
for (int i = 0; i <arrThreads.length; i++)
{
arrThreads[i] = new MeuThread();
arrThreads[i].id = i;
arrThreads[i].setDaemon(true);
arrThreads[i].start();
}
Thread.sleep(500);
for (int i = 0; i <arrThreads.length; i++)
{
sincronizado(arrThreads[i])
{
arrThreads[i].notify();
}
}
}
private static void notifyTest2() lança InterruptedException
{
MeuRunner[] arrMyRunners = new MeuRunner[3];
Thread[] arrThreads = new Thread[3];
for (int i = 0; i <arrThreads.length; i++)
{
arrMyRunners[i] = new MyRunner();
arrMyRunners[i].id = i;
arrThreads[i] = new Thread(arrMyRunners[i]);
arrThreads[i].setDaemon(true);
arrThreads[i].start();
}
Thread.sleep(500);
for (int i = 0; i <arrMyRunners.length; i++)
{
sincronizado(arrMyRunners[i])
{
arrMyRunners[i].notify();
}
}
}
private static void notifyTest3() lança InterruptedException
{
Corredor MyRunner = new MyRunner();
Thread[] arrThreads = new Thread[3];
for (int i = 0; i <arrThreads.length; i++)
{
arrThreads[i] = new Thread(corredor);
arrThreads[i].setDaemon(true);
arrThreads[i].start();
}
Thread.sleep(500);
sincronizado (corredor)
{
runner.notifyAll();
}
}
}
classe MyThread estende Thread
{
id interno público = 0;
execução de vazio público ()
{
System.out.println("Thread " + id + " está pronto para dormir por 5 minutos.");
tentar
{
sincronizado (este)
{
isto.espera(5*60*1000);
}
}
catch(InterruptedException ex)
{
ex.printStackTrace();
}
System.out.println("O "th" + id + "thread foi despertado.");
}
}
classe MyRunner implementa Runnable
{
id interno público = 0;
execução de vazio público ()
{
System.out.println("Thread " + id + " está pronto para dormir por 5 minutos.");
tentar
{
sincronizado (este)
{
isto.espera(5*60*1000);
}
}
catch(InterruptedException ex)
{
ex.printStackTrace();
}
System.out.println("O "th" + id + "thread foi despertado.");
}
}
O método notifyAll é adequado para o cenário de "multithread de objeto único", porque o método notify ativará aleatoriamente apenas um thread no objeto.
Troca de estado de thread
Para um thread, desde o momento em que o criamos até o término do thread, o status do thread durante esse processo pode ser assim:
Criação: Já existe uma instância de Thread, mas a CPU ainda possui recursos e intervalos de tempo alocados para ela.
Pronto: A thread obteve todos os recursos necessários para rodar e está apenas aguardando a CPU agendar o horário.
Em execução: o thread está localizado no intervalo de tempo atual da CPU e está executando a lógica relacionada.
Sleep: geralmente o estado após chamar Thread.sleep. Neste momento, o thread ainda contém vários recursos necessários para a operação, mas não será agendado pela CPU.
Suspender: Geralmente o estado após chamar Thread.suspend Semelhante ao sleep, a CPU não irá agendar o thread.
Morte: O thread termina ou o método Thread.stop é chamado.
A seguir demonstraremos como mudar os estados do thread. Primeiro usaremos o seguinte método:
Thread() ou Thread(Runnable): Construa um thread.
Thread.start: inicia um tópico.
Thread.sleep: Muda o thread para o estado de suspensão.
Thread.interrupt: Interrompe a execução do thread.
Thread.join: Aguarde o término de um thread.
Thread.yield: Priva o thread de sua fatia de tempo de execução na CPU e aguarda o próximo agendamento.
Object.wait: bloqueia todos os threads no objeto e não continuará em execução até o método de notificação.
Object.notify: ativa aleatoriamente um thread no objeto.
Object.notifyAll: ativa todos os threads no Object.
Agora é hora da demonstração! ! !
Tópico esperando e acordando
Os métodos Object.wait e Object.notify são usados principalmente aqui, consulte a instância de notificação acima. Deve-se observar que wait e notify devem ter como alvo o mesmo objeto. Quando criamos um thread implementando a interface Runnable, devemos usar esses dois métodos no objeto Runnable em vez do objeto Thread.
Tópico dormindo e acordando
public static void main(String[] args) lança InterruptedException
{
sleepTest();
}
private static void sleepTest() lança InterruptedException
{
Tópico tópico = novo Tópico()
{
execução de vazio público ()
{
System.out.println("Thread" + Thread.currentThread().getName() + "Ele ficará suspenso por 5 minutos.");
tentar
{
Thread.sleep(5*60*1000);
}
catch(InterruptedException ex)
{
System.out.println("Thread" + Thread.currentThread().getName() + "O sono foi interrompido.");
}
System.out.println("Thread" + Thread.currentThread().getName() + "Suspensão encerrada.");
}
};
thread.setDaemon(verdadeiro);
thread.start();
Thread.sleep(500);
thread.interrupt();
}
}
Embora exista um método Thread.stop, esse método não é recomendado. Podemos usar o mecanismo de suspensão e ativação acima para permitir que o thread termine o thread ao processar IterruptedException.
public static void main(String[] args) lança InterruptedException
{
stopTest();
}
private static void stopTest() lança InterruptedException
{
Tópico tópico = novo Tópico()
{
execução de vazio público ()
{
System.out.println("O thread está em execução.");
tentar
{
Thread.sleep(1*60*1000);
}
catch(InterruptedException ex)
{
System.out.println("Interrupção de thread, finalização de thread");
retornar;
}
System.out.println("O thread terminou normalmente.");
}
};
thread.start();
Thread.sleep(500);
thread.interrupt();
}
}
Quando criamos 10 subthreads no thread principal e esperamos que depois que todos os 10 subthreads forem concluídos, o thread principal executará a próxima lógica. Neste momento, é hora de Thread.join aparecer.
public static void main(String[] args) lança InterruptedException
{
joinTest();
}
private static void joinTest() lança InterruptedException
{
Tópico tópico = novo Tópico()
{
execução de vazio público ()
{
tentar
{
para(int i = 0; i < 5; i++)
{
System.out.println("O thread está em execução.");
Thread.sleep(1000);
}
}
catch(InterruptedException ex)
{
ex.printStackTrace();
}
}
};
thread.setDaemon(verdadeiro);
thread.start();
Thread.sleep(1000);
thread.join();
System.out.println("O thread principal terminou normalmente.");
}
}
Sabemos que todos os threads em um processo compartilham espaço de memória, então como transferimos mensagens entre diferentes threads? Ao revisar o Java I/O, falamos sobre PipedStream e PipedReader, e é aqui que eles entram em ação.
Os dois exemplos a seguir têm exatamente as mesmas funções. A diferença é que um usa Stream e o outro usa Reader/Writer.
Tópico thread1 = novo Tópico()
{
execução de vazio público ()
{
BufferedReader br = novo BufferedReader(new InputStreamReader(System.in));
tentar
{
enquanto (verdadeiro)
{
String mensagem = br.readLine();
pos.write(message.getBytes());
if (message.equals("end")) break;
}
close();
pos.close();
}
catch(Exceção ex)
{
ex.printStackTrace();
}
}
};
Tópico thread2 = novo Tópico()
{
execução de vazio público ()
{
byte[] buffer = novo byte[1024];
int bytesLeitura = 0;
tentar
{
while((bytesRead = pis.read(buffer, 0, buffer.length)) != -1)
{
System.out.println(nova String(buffer));
if (new String(buffer).equals("end")) break;
buffer = nulo;
buffer = novo byte[1024];
}
pis.close();
buffer = nulo;
}
catch(Exceção ex)
{
ex.printStackTrace();
}
}
};
thread1.setDaemon(verdadeiro);
thread2.setDaemon(true);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
}
Tópico thread1 = novo Tópico()
{
execução de vazio público ()
{
BufferedReader br = novo BufferedReader(new InputStreamReader(System.in));
tentar
{
enquanto (verdadeiro)
{
String mensagem = br.readLine();
bw.write(mensagem);
bw.newLine();
bw.flush();
if (message.equals("end")) break;
}
close();
close();
close();
}
catch(Exceção ex)
{
ex.printStackTrace();
}
}
};
Tópico thread2 = novo Tópico()
{
execução de vazio público ()
{
Linha de string = nulo;
tentar
{
while((linha = br.readLine()) != nulo)
{
System.out.println(linha);
if (line.equals("end")) break;
}
close();
pr.fechar();
}
catch(Exceção ex)
{
ex.printStackTrace();
}
}
};
thread1.setDaemon(verdadeiro);
thread2.setDaemon(true);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
}