DEV Community

Comunicação entre threads com o uso de notify( ), wait( ) e notifyAll( )

Situação:
Thread T precisa de um recurso R indisponível enquanto executa um método sincronizado.
Laços de sondagem não são ideais, pois bloqueiam o objeto, limitando o multitarefa.

Solução:
T abandona temporariamente o controle do objeto.
Outra thread pode ser executada enquanto T aguarda notificação para retomar.

Comunicação entre threads:
Usada para notificar e reativar threads bloqueadas.
Suporte em Java por meio dos métodos wait(), notify() e notifyAll().

Regras de uso:
Esses métodos pertencem à classe Object e devem ser usados dentro de blocos sincronizados.
wait() suspende a thread e libera o monitor para outra thread.
notify() reativa uma única thread em espera.
notifyAll() reativa todas as threads em espera (prioridade mais alta é executada).

Formas de wait():
wait() – espera indefinidamente até notificação.
wait(long millis) – espera por notificação ou até expirar o tempo especificado.
wait(long millis, int nanos) – espera com precisão de nanossegundos.

Cuidado com ativações falsas:
Chamadas a wait() podem ser ativadas por engano.
Recomendação: sempre verificar a condição esperada dentro de um laço.

Exemplo que usa wait( ) e notify( )

  • Contexto: Criar um programa que simula o tique-taque de um relógio.

Classe principal:
Nome: TickTock.
Métodos:
tick(): Exibe a palavra "Tick".
tock(): Exibe a palavra "Tock".

Execução:
Duas threads são criadas:
Uma chama o método tick().
Outra chama o método tock().

Objetivo: Garantir a execução coordenada das threads para exibir um padrão coerente de "Tick" seguido por "Tock".

Image description

Image description

Image description

Image description

Classe principal (TickTock):
Contém dois métodos principais: tick() e tock().
Propósito: Garantir alternância entre "Tick" e "Tock".
Utiliza o campo state para armazenar o estado atual: "ticked" ou "tocked".

Execução em main():
Cria um objeto TickTock chamado tt.
Duas threads (Tick e Tock) são iniciadas, baseadas na classe MyThread.

Classe MyThread:
Recebe como argumentos:
O nome da thread ("Tick" ou "Tock").
Referência ao objeto TickTock (tt).
O método run() decide se chama tick() ou tock() com base no nome da thread.
Faz cinco chamadas aos métodos com true para mantê-los ativos.
Uma chamada final com false interrompe o relógio.

Mecanismo de sincronização:
Os métodos tick() e tock() de TickTock garantem a alternância usando o campo state e os métodos wait() e notify().
tick() espera que state seja "tocked" antes de avançar, e vice-versa em tock().

Image description

  • tick() modificado com synchronized: Necessário porque wait() e notify() só podem ser usados em métodos sincronizados.

Parâmetro running: Controla o desligamento do relógio. Se running for false, tick() define state como "ticked", chama notify() e retorna.

Funcionamento normal:

  • Exibe "Tick".

  • Define state como "ticked".

  • Chama notify() para liberar outra thread que está esperando.

  • Entra em suspensão com wait(), aguardando que outra thread chame notify().

Laço while com wait():

  • Garante que wait() só continue quando state for "tocked".

  • Previne ativações falsas, que poderiam fazer a thread reiniciar incorretamente.

tock():

  • Similar a tick(), mas exibe "Tock" e define state como "tocked".

  • Mantém o sincronismo, alternando entre tick() e tock().

Chamada a notify() ao desligar:

  • Necessária para liberar threads que estão aguardando quando o relógio é interrompido.

  • Sem essa chamada, o programa pode "travar", pois uma thread aguardará indefinidamente.

Teste sem wait() e notify():

  • O programa não sincronizará corretamente o "Tick" e "Tock".

  • Resultado: Desordem na execução das mensagens.

Image description

Os métodos tick() e tock() não estão mais sincronizados entre si. Isso significa que eles podem ser executados independentemente, sem garantir que um "Tick" seja seguido por um "Tock" ou vice-versa.

Top comments (0)