Costumo navegar. Em relação ao notificar e notificar todos em Java, as pessoas geralmente têm as seguintes declarações:
Notificar apenas notificará um objeto esperando, enquanto o notificação notificará todos os objetos que estão esperando e todos os objetos continuarão sendo executados.
E parece que existem exemplos para provar isso. Pode -se dizer que a declaração acima está correta ou não. A razão é que um deles é muito importante. A declaração oficial é a seguinte:
Espere, notifique, notifiquel:
Este método deve ser chamado apenas por um thread que é o proprietário deste monitor de objeto. Um tópico pode se tornar o proprietário deste monitor de objeto de uma de três maneiras:
Executando o método de instância síncrona desse objeto.
O corpo da instrução sincronizado é executado executando a instrução sincronizada nesse objeto.
Para objetos da classe de tipo, você pode executar métodos estáticos síncronos da classe.
Apenas um thread possui um monitor de objeto por vez.
A declaração acima é extraída de Javadoc. Isso significa que, na chamada, o monitor de objeto (ou seja, bloqueio) deve ser mantido, o que podemos entender como em execução dentro do método sincronizado. Então, o significado implícito dessa declaração é que, se você deseja continuar o bloco de código contido no bloco de sincronização, precisará reaquar o bloqueio. Esta frase é descrita em Javadoc:
espere
Este método faz com que o encadeamento atual (chamado T) se colocasse no conjunto de espera do objeto e, em seguida, abandone todos os requisitos de sincronização nesse objeto. Para fins de agendamento de threads, o Thread T está desativado e está em hibernação antes que uma das quatro situações a seguir ocorra:
Alguns outros threads chamam o método Notify desse objeto, e o thread t passa a ser selecionado opcionalmente como o thread de despertar.
Alguns outros threads chamam o método NotifyAll desse objeto.
Algum outro thread interrompe o thread t.
Aproximadamente o tempo real especificado foi alcançado. No entanto, se o tempo limite for zero, o tempo real não será levado em consideração e o thread aguardará até que a notificação seja obtida.
Em seguida, o thread t é excluído do conjunto de espera do objeto e a programação do thread é executada novamente. O thread compete com outros threads de maneira convencional para obter o direito de sincronizar o objeto; Depois que o controle sobre o objeto é obtido, todas as suas declarações de sincronização no objeto serão restauradas em seu estado anterior, que é chamar a espera
A situação em que o método é. O thread t retorna da chamada para o método de espera. Portanto, ao retornar do método de espera, o estado de sincronização do objeto e do encadeamento t é exatamente o mesmo que chamando o método de espera.
Ou seja, o bloqueio deve ser re-montado, para que, para o NotifyAll, todos os threads tenham sido notificados. No entanto, esses threads competirão e apenas um thread adquirirá com sucesso o bloqueio. Antes que este thread seja executado, outros threads devem esperar (mas não há necessidade de notificar todas as notificações aqui, porque é notificado e é necessário apenas adquirir o bloqueio). Há o código a seguir que pode reproduzir esse fenômeno.
Primeiro, defina uma classe de threads que pode ser executada, como segue:
objeto final estático privado obj = new Object (); A classe estática R implementa runnable {int i; R (int i) {this.i = i; } public void run () {try {synchronized (obj) {System.out.println ("Thread->" + i + "waiting"); obj.wait (); System.out.println ("Thread->" + i + "Running"); Thread.sleep (30000); }} catch (Exceção e) {e.printStackTrace (); }}} Preste atenção ao interior do método de execução acima. Depois de esperar (), imprimimos uma frase e, em seguida, pausamos o código atual por 30 segundos. Em relação ao método do sono, é descrito da seguinte maneira:
O tópico não perde a propriedade de nenhum monitor.
Ou seja, a fechadura ainda é mantida.
Em seguida, defina um método principal para executar esses threads da seguinte maneira:
Thread [] rs = novo thread [10]; for (int i = 0; i <10; i ++) {rs [i] = novo thread (novo r (i)); } para (Thread R: RS) {R.Start (); } Thread.sleep (5000); sincronizado (obj) {obj.NotifyAll (); }Definimos 10 threads e depois executamos todos eles. Como há espera, 10 threads esperarão após a impressão de "Start Run". Em seguida, o método principal chama NotifyAll. A saída aqui aparecerá da seguinte forma:
Thread-> 0 Esperando por thread-> 4 esperando por thread-> 5 esperando por thread-> 3 esperando por thread-> 2 esperando por thread-> 1 esperando por thread-> 6 esperando por thread-> 7 esperando por thread-> 8 aguardando thread-> 9 esperando por thread-> 9 em execução
... Nenhuma outra saída dentro de 30 segundos
Na saída acima, após a espera, apenas um encadeamento produz a instrução "em execução" e, por um período de tempo (30 segundos aqui), não haverá outra saída. Ou seja, outros threads não serão lançados entre os bloqueios mantidos pelo código atual.
A conclusão final é: se o tópico de espera quiser continuar correndo, ele deve atender a duas condições:
O outro thread notificou ou notifica todos os notificados e o thread atual foi notificado.
Depois de competir com outros threads a bloquear, duas condições foram obtidas com sucesso para o bloqueio, e nenhum deles estava faltando. De fato, no nível de implementação, notifique e notifique todos os mesmos efeitos, e um thread continuará sendo executado. Mas notifyAll está isento. A necessidade de notificar outros threads após a execução do thread, porque foi notificado. Quando usar o Notify e quando usar o NotifyAll, depende da situação real.
O exposto acima é uma compilação das informações para o Java Notify e NotifyAll. Continuaremos a adicionar informações relevantes no futuro. Obrigado pelo seu apoio a este site!