Qualquer aplicativo pode ter vários processos (instâncias). Cada um desse processo pode ser atribuído como um único thread ou vários threads. Veremos neste tutorial como realizar várias tarefas ao mesmo tempo e também aprenderemos mais sobre threads e sincronização entre threads.
Neste tutorial, aprenderemos:
- O que é Single Thread
- O que é multithreading em Java?
- Ciclo de vida do thread em Java
- Java Thread Synchronization
- Exemplo de multithreading Java
O que é Single Thread?
Um único thread é basicamente leve e a menor unidade de processamento. Java usa threads usando uma "Classe de Thread".
Existem dois tipos de thread - thread do usuário e thread daemon (threads daemon são usados quando queremos limpar o aplicativo e são usados em segundo plano).
Quando um aplicativo é iniciado pela primeira vez, o thread do usuário é criado. Poste isso, podemos criar muitos threads de usuário e threads daemon.
Exemplo de thread único:
pacote demotest;public class GuruThread{public static void main (String [] args) {System.out.println ("Single Thread");}}
Vantagens do single thread:
- Reduz a sobrecarga no aplicativo como thread único executado no sistema
- Além disso, reduz o custo de manutenção do aplicativo.
O que é multithreading em Java?
MULTITHREADING em Java é um processo de execução de dois ou mais threads simultaneamente para utilização máxima da CPU. Os aplicativos multithread executam dois ou mais threads executados simultaneamente. Por isso, também é conhecido como Simultaneidade em Java. Cada thread corre paralelamente entre si. Threads múltiplos não alocam área de memória separada, portanto, eles economizam memória. Além disso, a alternância de contexto entre threads leva menos tempo.
Exemplo de multi thread:
pacote demotest;public class GuruThread1 implementa Runnable{public static void main (String [] args) {Thread guruThread1 = new Thread ("Guru1");Thread guruThread2 = new Thread ("Guru2");guruThread1.start ();guruThread2.start ();System.out.println ("Os nomes dos threads são os seguintes:");System.out.println (guruThread1.getName ());System.out.println (guruThread2.getName ());}@Sobreporpublic void run () {}}
Vantagens do multithread:
- Os usuários não são bloqueados porque os threads são independentes e podemos realizar várias operações às vezes
- Como tal, os threads são independentes, os outros threads não serão afetados se um thread encontrar uma exceção.
Ciclo de vida do thread em Java
O ciclo de vida de um tópico:
Existem vários estágios do ciclo de vida da rosca, conforme mostrado no diagrama acima:
- Novo
- Executável
- Correndo
- Espera
- Morto
- Novo: Nesta fase, o thread é criado usando a classe "Thread class". Ele permanece neste estado até que o programa inicie o thread. Também é conhecido como fio nascido.
- Executável: nesta página, a instância do thread é chamada com um método de início. O controle de thread é fornecido ao planejador para finalizar a execução. Depende do planejador, se deseja executar o segmento.
- Em execução: quando o thread começa a ser executado, o estado é alterado para "em execução". O planejador seleciona um encadeamento do conjunto de encadeamentos e começa a ser executado no aplicativo.
- Em espera: este é o estado em que um thread tem que esperar. Como há vários threads em execução no aplicativo, há uma necessidade de sincronização entre os threads. Conseqüentemente, um thread tem que esperar, até que o outro thread seja executado. Portanto, esse estado é conhecido como estado de espera.
- Dead: Este é o estado em que o thread é encerrado. O encadeamento está em estado de execução e, assim que concluiu o processamento, está em "estado morto".
Alguns dos métodos comumente usados para threads são:
Método | Descrição |
---|---|
começar() | Este método inicia a execução do encadeamento e a JVM chama o método run () no encadeamento. |
Sleep (int milissegundos) | Este método faz o encadeamento hibernar, portanto, a execução do encadeamento pausará por milissegundos fornecidos e depois disso, novamente o encadeamento começa a ser executado. Isso ajuda na sincronização dos threads. |
getName () | Ele retorna o nome do segmento. |
setPriority (int newpriority) | Ele muda a prioridade do segmento. |
produzem () | Isso faz com que o thread atual seja interrompido e outros threads sejam executados. |
Exemplo: Neste exemplo, vamos criar um encadeamento e explorar os métodos integrados disponíveis para os encadeamentos.
pacote demotest;public class thread_example1 implementa Runnable {@Sobreporpublic void run () {}public static void main (String [] args) {Tópico guruthread1 = novo Tópico ();guruthread1.start ();tentar {guruthread1.sleep (1000);} catch (InterruptedException e) {// TODO bloco de captura gerado automaticamentee.printStackTrace ();}guruthread1.setPriority (1);int gurupriority = guruthread1.getPriority ();System.out.println (gurupriority);System.out.println ("Thread em execução");}}
Explicação do código:
- Linha de código 2: Estamos criando uma classe "thread_Example1" que está implementando a interface Runnable (ela deve ser implementada por qualquer classe cujas instâncias sejam executadas pelo thread).
- Linha de código 4: substitui o método de execução da interface executável, pois é obrigatório substituir esse método
- Linha de código 6: Aqui definimos o método principal no qual iniciaremos a execução da thread.
- Linha de código 7: Aqui estamos criando um novo nome de thread como "guruthread1" instanciando uma nova classe de thread.
- Linha de código 8: usaremos o método "start" do thread usando a instância "guruthread1". Aqui, o thread começará a ser executado.
- Linha de código 10: Aqui estamos usando o método "sleep" do thread usando a instância "guruthread1". Portanto, o encadeamento ficará inativo por 1000 milissegundos.
- Código 9-14: Aqui colocamos o método sleep no bloco try catch, pois há exceção verificada que ocorre, ou seja, exceção interrompida.
- Linha de código 15: aqui, estamos definindo a prioridade do segmento para 1 de qualquer prioridade que ele era
- Linha de código 16: aqui estamos obtendo a prioridade da thread usando getPriority ()
- Linha de código 17: aqui estamos imprimindo o valor obtido em getPriority
- Linha de código 18: Aqui estamos escrevendo um texto que o thread está executando.
Ao executar o código acima, você obtém a seguinte saída:
Resultado:
5 é a prioridade do Thread e Thread Running é o texto que é a saída do nosso código.
Java Thread Synchronization
No multithreading, existe o comportamento assíncrono dos programas. Se um thread está gravando alguns dados e outro thread que está lendo dados ao mesmo tempo, pode criar inconsistência no aplicativo.
Quando há necessidade de acessar os recursos compartilhados por dois ou mais threads, a abordagem de sincronização é utilizada.
Java forneceu métodos sincronizados para implementar o comportamento sincronizado.
Nesta abordagem, uma vez que o thread atinge dentro do bloco sincronizado, nenhum outro thread pode chamar esse método no mesmo objeto. Todos os threads têm que esperar até que o thread termine o bloco sincronizado e saia dele.
Desta forma, a sincronização auxilia em uma aplicação multithread. Um thread tem que esperar até que outro thread termine sua execução, somente então os outros threads têm permissão para execução.
Ele pode ser escrito da seguinte forma:
Sincronizado (objeto){// Bloco de instruções a serem sincronizadas}
Exemplo de multithreading Java
Neste exemplo, pegaremos dois encadeamentos e buscaremos os nomes do encadeamento.
Exemplo 1:
GuruThread1.javapacote demotest;public class GuruThread1 implementa Runnable {/ *** @param args* /public static void main (String [] args) {Thread guruThread1 = new Thread ("Guru1");Thread guruThread2 = new Thread ("Guru2");guruThread1.start ();guruThread2.start ();System.out.println ("Os nomes dos threads são os seguintes:");System.out.println (guruThread1.getName ());System.out.println (guruThread2.getName ());}@Sobreporpublic void run () {}}
Explicação do código:
- Linha de código 3: pegamos uma classe "GuruThread1" que implementa Runnable (deve ser implementado por qualquer classe cujas instâncias sejam executadas pelo thread).
- Linha de código 8: este é o método principal da classe
- Linha de código 9: Aqui estamos instanciando a classe Thread, criando uma instância chamada "guruThread1" e criando uma thread.
- Linha de código 10: Aqui estamos instanciando a classe Thread, criando uma instância chamada "guruThread2" e criando uma thread.
- Linha de código 11: estamos iniciando o tópico, ou seja, guruThread1.
- Linha de código 12: estamos iniciando o tópico, ou seja, guruThread2.
- Linha de código 13: Saída do texto como "Os nomes dos threads são os seguintes:"
- Linha de código 14: Obtendo o nome do thread 1 usando o método getName () da classe de thread.
- Linha de código 15: Obtendo o nome do thread 2 usando o método getName () da classe de thread.
Ao executar o código acima, você obtém a seguinte saída:
Resultado:
Os nomes dos tópicos estão sendo produzidos aqui como
- Guru1
- Guru2
Exemplo 2:
Neste exemplo, aprenderemos sobre como substituir os métodos run () e start () de uma interface executável e criar dois threads dessa classe e executá-los de acordo.
Além disso, estamos tendo duas aulas,
- Um que irá implementar a interface executável e
- Outro que terá o método principal e será executado de acordo.
pacote demotest;public class GuruThread2 {public static void main (String [] args) {// TODO stub do método gerado automaticamenteGuruThread3 threadguru1 = new GuruThread3 ("guru1");threadguru1.start ();GuruThread3 threadguru2 = novo GuruThread3 ("guru2");threadguru2.start ();}}class GuruThread3 implementa Runnable {Thread guruthread;private String guruname;GuruThread3 (nome da string) {guruname = nome;}@Sobreporpublic void run () {System.out.println ("Thread em execução" + guruname);para (int i = 0; i <4; i ++) {System.out.println (i);System.out.println (guruname);tentar {Thread.sleep (1000);} catch (InterruptedException e) {System.out.println ("Thread foi interrompido");}}}public void start () {System.out.println ("Thread iniciado");if (guruthread == null) {guruthread = novo Tópico (este, guruname);guruthread.start ();}}}
Explicação do código:
- Linha de código 2: Aqui estamos tendo uma classe "GuruThread2" que terá o método principal nela.
- Linha de código 4: Aqui estamos pegando um método principal da classe.
- Linha de código 6-7: Aqui estamos criando uma instância da classe GuruThread3 (que é criada nas linhas abaixo do código) como "threadguru1" e estamos iniciando o thread.
- Linha de código 8-9: Aqui estamos criando outra instância da classe GuruThread3 (que é criada nas linhas abaixo do código) como "threadguru2" e estamos iniciando o thread.
- Linha de código 11: aqui estamos criando uma classe "GuruThread3" que está implementando a interface executável (ela deve ser implementada por qualquer classe cujas instâncias sejam executadas pelo thread).
- Linha de código 13-14: estamos pegando duas variáveis de classe, uma da classe thread e a outra classe string.
- Linha de código 15-18: estamos substituindo o construtor GuruThread3, que recebe um argumento como tipo de string (que é o nome dos threads) que é atribuído à variável de classe guruname e, portanto, o nome do thread é armazenado.
- Linha de código 20: Aqui, estamos substituindo o método run () da interface executável.
- Linha de código 21: estamos gerando o nome do thread usando a instrução println.
- Linha de código 22-31: Aqui estamos usando um loop for com contador inicializado em 0 e não deve ser menor que 4 (podemos pegar qualquer número, portanto, aqui o loop será executado 4 vezes) e incrementando o contador. Estamos imprimindo o nome do thread e também fazendo o thread hibernar por 1000 milissegundos dentro de um bloco try-catch, pois o método sleep levantou uma exceção verificada.
- Linha de código 33: Aqui estamos substituindo o método de início da interface executável.
- Linha de código 35: Estamos gerando o texto "Thread started".
- Linha de código 36-40: Aqui estamos pegando uma condição if para verificar se a variável de classe guruthread tem valor nela ou não. Se for nulo, então estamos criando uma instância usando a classe de thread que leva o nome como um parâmetro (valor para o qual foi atribuído no construtor). Após o qual o thread é iniciado usando o método start ().
Ao executar o código acima, você obtém a seguinte saída:
Produto :
Existem dois tópicos, portanto, recebemos duas vezes a mensagem "Tópico iniciado".
Obtemos os nomes do thread conforme os geramos.
Ele vai para o loop for onde estamos imprimindo o contador e o nome do thread e o contador começa com 0.
O loop é executado três vezes e entre o thread é suspenso por 1000 milissegundos.
Portanto, primeiro, obtemos guru1, depois guru2, depois, novamente guru2, porque o thread dorme aqui por 1000 milissegundos e, em seguida, guru1 e novamente guru1, o thread dorme por 1000 milissegundos, então temos guru2 e, em seguida, guru1.
Resumo :
Neste tutorial, vimos aplicativos multithread em Java e como usar um e vários threads.
- No multithreading, os usuários não são bloqueados, pois os threads são independentes e podem realizar várias operações ao mesmo tempo
- Vários estágios do ciclo de vida do segmento são,
- Novo
- Executável
- Correndo
- Espera
- Morto
- Também aprendemos sobre a sincronização entre threads, o que ajuda o aplicativo a funcionar sem problemas.
- O multithreading torna muito mais fáceis as tarefas do aplicativo.