Si uno busca en Google "diferencia entre notify()
y notifyAll()
", aparecerán muchas explicaciones (dejando aparte los párrafos de javadoc). Todo se reduce a la cantidad de hilos en espera que se están despertando: uno adentro notify()
y todo adentro notifyAll()
.
Sin embargo (si entiendo la diferencia entre estos métodos correctamente), solo se selecciona un subproceso para una mayor adquisición del monitor; en el primer caso, el seleccionado por la VM, en el segundo caso, el seleccionado por el planificador de subprocesos del sistema. El programador desconoce los procedimientos de selección exactos para ambos (en el caso general).
¿Cuál es la utilidad diferencia entre notificar () y notify () , entonces? ¿Me estoy perdiendo de algo?
java
multithreading
Sergey Mikhanov
fuente
fuente
synchronized
, a excepción de ciertos , casos de uso bastante raros.notifyAll()
caso, los otros subprocesos después del primero permanecen despiertos y adquirirán el monitor, uno por uno. En elnotify
caso, ninguno de los otros hilos se ha despertado. ¡Funcionalmente son muy diferentes!blocked
y nowaiting
. Cuandoblocked
su ejecutivo se suspende temporalmente hasta que otro hilo esté dentro delsync
bloque.Respuestas:
Eso no es correcto.
o.notifyAll()
despierta todos los hilos que están bloqueados en laso.wait()
llamadas. Los hilos solo pueden regresaro.wait()
uno por uno, pero cada uno tendrá su turno.En pocas palabras, depende de por qué sus hilos están esperando ser notificados. ¿Desea contarle a uno de los hilos de espera que sucedió algo o quiere contarles todos al mismo tiempo?
En algunos casos, todos los hilos de espera pueden tomar medidas útiles una vez que finaliza la espera. Un ejemplo sería un conjunto de subprocesos que esperan que finalice una determinada tarea; Una vez que la tarea ha finalizado, todos los hilos en espera pueden continuar con sus negocios. En tal caso, utilizaría notifyAll () para activar todos los hilos en espera al mismo tiempo.
Otro caso, por ejemplo, el bloqueo mutuamente exclusivo, solo uno de los hilos en espera puede hacer algo útil después de ser notificado (en este caso, adquirir el bloqueo). En tal caso, preferiría utilizar notify () . Implementado correctamente, también podría utilizar notifyAll () en esta situación, pero despertaría innecesariamente hilos que de todos modos no pueden hacer nada.
En muchos casos, el código para esperar una condición se escribirá como un bucle:
De esa manera, si una
o.notifyAll()
llamada despierta más de un hilo en espera, y el primero que regresa de laso.wait()
marcas deja la condición en el estado falso, entonces los otros hilos que se despertaron volverán a esperar.fuente
Claramente,
notify
despierta (cualquier) un hilo en el conjunto de espera,notifyAll
despierta todos los hilos en el conjunto de espera. La siguiente discusión debería aclarar cualquier duda.notifyAll
debe usarse la mayor parte del tiempo. Si no está seguro de cuál usar, usenotifyAll
. Consulte la explicación que sigue.Lea con mucho cuidado y comprenda. Por favor envíeme un correo electrónico si tiene alguna pregunta.
Mire al productor / consumidor (la suposición es una clase ProducerConsumer con dos métodos). ESTÁ ROTO (porque usa
notify
), sí, PUEDE funcionar, incluso la mayoría de las veces, pero también puede causar un punto muerto; veremos por qué:PRIMERAMENTE,
¿Por qué necesitamos un bucle while que rodea la espera?
Necesitamos un
while
bucle en caso de que tengamos esta situación:El consumidor 1 (C1) ingresa el bloque sincronizado y el búfer está vacío, por lo que C1 se coloca en el conjunto de espera (a través de la
wait
llamada). El consumidor 2 (C2) está a punto de ingresar el método sincronizado (en el punto Y anterior), pero el productor P1 coloca un objeto en el búfer y luego llamanotify
. El único subproceso en espera es C1, por lo que se despierta y ahora intenta volver a adquirir el bloqueo del objeto en el punto X (arriba).Ahora C1 y C2 están intentando adquirir el bloqueo de sincronización. Se elige uno de ellos (de manera no determinista) y se ingresa al método, el otro se bloquea (no espera, pero se bloquea, tratando de obtener el bloqueo del método). Digamos que C2 obtiene el bloqueo primero. C1 sigue bloqueando (tratando de adquirir el bloqueo en X). C2 completa el método y libera el bloqueo. Ahora, C1 adquiere la cerradura. Adivina qué, por suerte tenemos un
while
bucle, porque, C1 realiza la verificación del bucle (guardia) y se le impide eliminar un elemento inexistente del búfer (¡C2 ya lo tiene!). Si no tuviéramos unwhile
, obtendríamos unIndexArrayOutOfBoundsException
mensaje cuando C1 intente eliminar el primer elemento del búfer.AHORA,
Ok, ahora ¿por qué necesitamos notificar a todos?
En el ejemplo anterior de productor / consumidor, parece que podemos salirse con la suya
notify
. Parece de esta manera, porque podemos demostrar que los guardias en los bucles de espera para el productor y el consumidor son mutuamente excluyentes. Es decir, parece que no podemos tener un hilo esperando tanto en elput
método como en elget
método, porque, para que eso sea cierto, lo siguiente debería ser cierto:buf.size() == 0 AND buf.size() == MAX_SIZE
(suponga que MAX_SIZE no es 0)SIN EMBARGO, esto no es lo suficientemente bueno, NECESITAMOS usarlo
notifyAll
. Veamos por qué ...Supongamos que tenemos un búfer de tamaño 1 (para que el ejemplo sea fácil de seguir). Los siguientes pasos nos llevan al punto muerto. Tenga en cuenta que en CUALQUIER MOMENTO un hilo se despierta con notificación, puede ser seleccionado de forma no determinista por la JVM, es decir, cualquier hilo en espera se puede despertar. También tenga en cuenta que cuando varios subprocesos están bloqueando la entrada a un método (es decir, tratando de adquirir un bloqueo), el orden de adquisición puede ser no determinista. Recuerde también que un hilo solo puede estar en uno de los métodos a la vez: los métodos sincronizados permiten que solo un hilo se ejecute (es decir, mantener el bloqueo de) cualquier método (sincronizado) en la clase. Si se produce la siguiente secuencia de eventos, se produce un punto muerto:
PASO 1:
- P1 pone 1 char en el búfer
PASO 2:
- Intentos de P2
put
- comprueba el ciclo de espera - ya es un char - esperaPASO 3:
- Intentos de P3
put
- comprueba el ciclo de espera - ya es un char - esperaPASO 4:
- C1 intenta obtener 1 char
- C2 intenta obtener 1 char - bloques al ingresar al
get
método- C3 intenta obtener 1 char - bloques al ingresar al
get
métodoPASO 5:
- C1 está ejecutando el
get
método - obtiene el método char, llamanotify
, sale-
notify
P2 se despierta- PERO, C2 ingresa al método antes de que P2 pueda (P2 debe recuperar el bloqueo), por lo que P2 se bloquea al ingresar al
put
método- C2 comprueba el bucle de espera, no hay más caracteres en el búfer, por lo que espera
: C3 ingresa al método después de C2, pero antes de P2, comprueba el bucle de espera, no hay más caracteres en el búfer, por lo que espera
PASO 6:
- AHORA: ¡hay P3, C2 y C3 esperando!
- Finalmente P2 adquiere el bloqueo, pone un char en el búfer, llama a notificar, sale del método
PASO 7:
- La notificación de P2 despierta a P3 (recuerde que cualquier subproceso se puede despertar)
- P3 verifica la condición del bucle de espera, ya hay un carácter en el búfer, por lo que espera.
- ¡NO HAY MÁS HILOS PARA LLAMAR NOTIFICACIÓN y TRES HILOS SUSPENDIDOS PERMANENTEMENTE!
SOLUCIÓN: Reemplace
notify
connotifyAll
en el código de productor / consumidor (arriba).fuente
notify
causas P3 (el subproceso seleccionado en este ejemplo) proceden del punto que estaba esperando (es decir, dentro delwhile
bucle). Hay otros ejemplos que no causan un punto muerto, sin embargo, en este caso, el uso denotify
no garantiza un código libre de punto muerto. El uso denotifyAll
hace.Diferencias útiles:
Use notify () si todos sus hilos de espera son intercambiables (el orden en que se despiertan no importa), o si solo tiene un hilo de espera. Un ejemplo común es un grupo de subprocesos utilizado para ejecutar trabajos desde una cola: cuando se agrega un trabajo, se notifica a uno de los subprocesos para que se active, ejecute el siguiente trabajo y vuelva a dormir.
Utilice notifyAll () para otros casos en los que los subprocesos en espera pueden tener diferentes propósitos y deberían poder ejecutarse simultáneamente. Un ejemplo es una operación de mantenimiento en un recurso compartido, donde varios subprocesos esperan que se complete la operación antes de acceder al recurso.
fuente
Creo que depende de cómo se producen y consumen los recursos. Si hay 5 objetos de trabajo disponibles a la vez y tiene 5 objetos de consumo, tendría sentido reactivar todos los subprocesos utilizando notifyAll () para que cada uno pueda procesar 1 objeto de trabajo.
Si solo tiene un objeto de trabajo disponible, ¿cuál es el punto de despertar todos los objetos de consumo para competir por ese único objeto? El primero que verifique el trabajo disponible lo obtendrá y todos los otros subprocesos lo comprobarán y descubrirán que no tienen nada que hacer.
Encontré una gran explicación aquí . En breve:
fuente
Tenga en cuenta que con las utilidades de concurrencia también tiene la opción de elegir entre estos métodos
signal()
ysignalAll()
cómo se llaman allí. Entonces la pregunta sigue siendo válida incluso conjava.util.concurrent
.Doug Lea plantea un punto interesante en su famoso libro : si a
notify()
yThread.interrupt()
sucede al mismo tiempo, la notificación podría perderse. Si esto puede suceder y tiene implicaciones dramáticas,notifyAll()
es una opción más segura a pesar de que paga el precio de los gastos generales (la mayoría de las veces se despierta demasiados hilos).fuente
Breve resumen:
Siempre prefiera notifyAll () sobre notify () a menos que tenga una aplicación paralela masiva en la que un gran número de subprocesos hagan lo mismo.
Explicación:
fuente: https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html
Compare notify () con notifyAll () en la situación descrita anteriormente: una aplicación masivamente paralela donde los hilos están haciendo lo mismo. Si llama a notifyAll () en ese caso, notifyAll () inducirá el despertar (es decir, la programación) de una gran cantidad de subprocesos, muchos de ellos innecesariamente (ya que solo un subproceso puede continuar, es decir, el subproceso al que se le otorgará el monitorear para el objeto wait () , notify () , o notifyAll () fue llamado sucesivamente), por lo tanto, el desperdicio de recursos de computación.
Por lo tanto, si no tiene una aplicación en la que una gran cantidad de subprocesos hacen lo mismo al mismo tiempo, prefiera notifyAll () sobre notify () . ¿Por qué? Porque, como otros usuarios ya han respondido en este foro, notifique ()
fuente: API Java SE8 ( https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#notify-- )
Imagine que tiene una aplicación de consumidor productor donde los consumidores están listos (es decir, esperando ) para consumir, los productores están listos (es decir, esperando ) para producir y la cola de artículos (para ser producida / consumida) está vacía. En ese caso, notify () podría despertar solo a los consumidores y nunca a los productores porque la elección de quién se despierta es arbitraria . El ciclo del consumidor productor no avanzaría, aunque los productores y los consumidores están listos para producir y consumir, respectivamente. En cambio, un consumidor se despierta (es decir, deja el estado de espera () ), no saca un artículo de la cola porque está vacío y notifica () a otro consumidor que continúe.
Por el contrario, notifyAll () despierta tanto a productores como a consumidores. La elección de quién está programado depende del planificador. Por supuesto, dependiendo de la implementación del planificador, el planificador también puede programar únicamente a los consumidores (por ejemplo, si asigna hilos de consumo con una prioridad muy alta). Sin embargo, la suposición aquí es que el peligro de que el planificador programe solo consumidores es menor que el peligro de que la JVM solo despierte a los consumidores porque cualquier planificador implementado razonablemente no toma decisiones arbitrarias . Por el contrario, la mayoría de las implementaciones de planificador hacen al menos algún esfuerzo para evitar la inanición.
fuente
Aquí hay un ejemplo. Ejecutarlo. Luego, cambie uno de notifyAll () para notificar () y ver qué sucede.
Clase ProducerConsumerExample
Clase Dropbox
Clase de consumo
Clase de productor
fuente
De Joshua Bloch, el propio Java Guru en Effective Java 2nd edition:
"Artículo 69: Prefiere utilidades de concurrencia para esperar y notificar".
fuente
Espero que esto aclare algunas dudas.
notify () : el método notify () activa un subproceso que espera el bloqueo (el primer subproceso que llamó a wait () en ese bloqueo).
notifyAll () : el método notifyAll () activa todos los subprocesos que esperan el bloqueo; JVM selecciona uno de los subprocesos de la lista de subprocesos que esperan el bloqueo y activa ese subproceso.
En el caso de un solo subproceso en espera de un bloqueo, no hay una diferencia significativa entre notify () y notifyAll (). Sin embargo, cuando hay más de un subproceso esperando el bloqueo, tanto en notify () como notifyAll (), el subproceso exacto despertado está bajo el control de la JVM y no puede controlar mediante programación el despertar un subproceso específico.
A primera vista, parece que es una buena idea simplemente llamar a notify () para activar un hilo; Puede parecer innecesario despertar todos los hilos. Sin embargo, el problema con notify () es que el hilo despertado podría no ser el adecuado para despertarse (el hilo podría estar esperando alguna otra condición, o la condición aún no se cumple para ese hilo, etc.). En ese caso , la notificación () podría perderse y ningún otro subproceso se despertará potencialmente dando lugar a un tipo de punto muerto (la notificación se pierde y todos los demás subprocesos esperan la notificación, para siempre).
Para evitar este problema , siempre es mejor llamar a notifyAll () cuando hay más de un subproceso esperando un bloqueo (o más de una condición en la que se realiza la espera). El método notifyAll () activa todos los hilos, por lo que no es muy eficiente. Sin embargo, esta pérdida de rendimiento es insignificante en las aplicaciones del mundo real.
fuente
Hay tres estados para un hilo.
Ahora, cuando se llama a notify (), JVM elige un subproceso y los mueve al estado BLOCKED y, por lo tanto, al estado RUNNING, ya que no hay competencia para el objeto monitor.
Cuando se llama a notifyAll (), JVM selecciona todos los subprocesos y los mueve al estado BLOCKED. Todos estos subprocesos obtendrán el bloqueo del objeto de forma prioritaria. El subproceso que pueda adquirir el monitor primero podrá ir al estado EN EJECUCIÓN primero y así sucesivamente.
fuente
Estoy muy sorprendido de que nadie haya mencionado el infame problema del "despertar perdido" (google it).
Básicamente:
ENTONCES, debe usar notifyAll a menos que tenga garantías comprobables de que la activación de la pérdida es imposible.
Un ejemplo común es una cola FIFO concurrente donde: múltiples colas (1. y 3. arriba) pueden hacer la transición de su cola de múltiples colas vacías a no vacías (2. arriba) pueden esperar la condición "la cola no está vacía" vacía -> no vacío debe notificar a los solicitantes
Puede escribir fácilmente un entrelazado de operaciones en el que, a partir de una cola vacía, interactúan 2 y 2 dequeuers, y 1 de ellos permanecerá dormido.
Este es un problema posiblemente comparable con el problema del punto muerto.
fuente
notify()
despertará un hilo mientrasnotifyAll()
despertará a todos. Que yo sepa, no hay término medio. Pero si no está seguro de quénotify()
hará con sus hilos, úselonotifyAll()
. Funciona como un encanto cada vez.fuente
Todas las respuestas anteriores son correctas, por lo que puedo decir, así que voy a decirte algo más. Para el código de producción, realmente debería usar las clases en java.util.concurrent. Hay muy poco que no puedan hacer por usted, en el área de concurrencia en Java.
fuente
notify()
te permite escribir código más eficiente quenotifyAll()
.Considere la siguiente pieza de código que se ejecuta desde múltiples hilos paralelos:
Se puede hacer más eficiente usando
notify()
:En el caso de que tenga una gran cantidad de subprocesos, o si la condición del bucle de espera es costosa de evaluar,
notify()
será significativamente más rápida quenotifyAll()
. Por ejemplo, si tiene 1000 subprocesos, se despertarán y evaluarán 999 subprocesos después del primeronotifyAll()
, luego 998, luego 997, y así sucesivamente. Por el contrario, con lanotify()
solución, solo se despertará un hilo.Úselo
notifyAll()
cuando necesite elegir qué hilo hará el trabajo a continuación:Finalmente, es importante comprender que, en caso de que
notifyAll()
, el código dentro de lossynchronized
bloques que se han despertado se ejecute secuencialmente, no todos a la vez. Digamos que hay tres hilos esperando en el ejemplo anterior, y el cuarto hilo llamanotifyAll()
. Los tres subprocesos se despertarán pero solo uno comenzará la ejecución y comprobará la condición delwhile
bucle. Si la condición estrue
, volverá a llamarwait()
, y solo entonces el segundo subproceso comenzará a ejecutarse y comprobará suwhile
condición de bucle, y así sucesivamente.fuente
Aquí hay una explicación más simple:
Tiene razón en que, ya sea que use notify () o notifyAll (), el resultado inmediato es que exactamente otro subproceso adquirirá el monitor y comenzará a ejecutarse. (Suponiendo que algunos hilos estén bloqueados en wait () para este objeto, otros hilos no relacionados no absorben todos los núcleos disponibles, etc.) El impacto llega más tarde.
Suponga que los hilos A, B y C estaban esperando este objeto, y el hilo A obtiene el monitor. La diferencia radica en lo que sucede una vez que A libera el monitor. Si usó notify (), entonces B y C todavía están bloqueados en wait (): no están esperando en el monitor, están esperando ser notificados. Cuando A suelta el monitor, B y C seguirán sentados allí, esperando una notificación ().
Si usó notifyAll (), entonces B y C han avanzado más allá del estado "esperar notificación" y ambos están esperando adquirir el monitor. Cuando A libera el monitor, B o C lo adquirirán (suponiendo que ningún otro subproceso esté compitiendo por ese monitor) y comenzarán a ejecutarse.
fuente
Esta respuesta es una reescritura gráfica y una simplificación de la excelente respuesta de xagyg , incluidos los comentarios de eran .
¿Por qué usar notifyAll, incluso cuando cada producto está destinado a un solo consumidor?
Considere productores y consumidores, simplificados de la siguiente manera.
Productor:
Consumidor:
Suponga que 2 productores y 2 consumidores comparten un búfer de tamaño 1. La siguiente imagen muestra un escenario que conduce a un punto muerto , que se evitaría si todos los hilos utilizados se notificaran a AllAll .
Cada notificación está etiquetada con el hilo que se está despertando.
fuente
Me gustaría mencionar lo que se explica en la concurrencia de Java en la práctica:
Primer punto, ¿Notify o NotifyAll?
Este problema se puede resolver con el uso del objeto Condición de bloqueo explícito de bloqueo, proporcionado en jdk 5, ya que proporciona una espera diferente para cada predicado de condición. Aquí se comportará correctamente y no habrá problemas de rendimiento, ya que llamará a la señal y se asegurará de que solo un subproceso esté esperando esa condición
fuente
notify()
- Selecciona un hilo aleatorio del conjunto de espera del objeto y lo coloca en elBLOCKED
estado. El resto de los subprocesos en el conjunto de espera del objeto todavía están en elWAITING
estado.notifyAll()
- Mueve todos los hilos del conjunto de espera del objeto alBLOCKED
estado. Después de usarnotifyAll()
, no quedan hilos en el conjunto de espera del objeto compartido porque todos ellos están ahora enBLOCKED
estado y no enWAITING
estado.BLOCKED
- bloqueado para la adquisición de la cerradura.WAITING
- esperando notificación (o bloqueado para completar la unión).fuente
Tomado del blog sobre Java efectivo:
Entonces, lo que entiendo es (del blog mencionado anteriormente, comentario de "Yann TM" sobre la respuesta aceptada y los documentos de Java ):
fuente
Echa un vistazo al código publicado por @xagyg.
Suponga que dos subprocesos diferentes esperan dos condiciones diferentes:
el primer subproceso está esperando
buf.size() != MAX_SIZE
y el segundo subproceso está esperandobuf.size() != 0
.Supongamos que en algún momento
buf.size()
no es igual a 0 . JVM llama ennotify()
lugar denotifyAll()
, y se notifica el primer subproceso (no el segundo).El primer subproceso se despierta, comprueba
buf.size()
cuáles podrían regresarMAX_SIZE
y vuelve a esperar. El segundo hilo no se despierta, continúa esperando y no llamaget()
.fuente
notify()
despierta el primer hilo que invocówait()
el mismo objeto.notifyAll()
despierta todos los hilos que llamaronwait()
al mismo objeto.El subproceso de mayor prioridad se ejecutará primero.
fuente
notify()
que no sea exactamente " el primer hilo ".Notificar notificará solo un subproceso que está en estado de espera, mientras que notificar a todos notificará a todos los subprocesos en estado de espera ahora todos los subprocesos notificados y todos los subprocesos bloqueados son elegibles para el bloqueo, de los cuales solo uno obtendrá el bloqueo y todos los demás (incluidos los que están en estado de espera antes) estarán en estado bloqueado.
fuente
Para resumir las excelentes explicaciones detalladas anteriores, y de la manera más simple que se me ocurre, esto se debe a las limitaciones del monitor incorporado JVM, que 1) se adquiere en toda la unidad de sincronización (bloque u objeto) y 2) no discrimina sobre la condición específica que se espera / notifica en / sobre.
Esto significa que si varios subprocesos están esperando en diferentes condiciones y se utiliza notify (), el subproceso seleccionado puede no ser el que avanzaría en la nueva condición cumplida, lo que provocaría que ese subproceso (y otros subprocesos actualmente en espera que pudieran para cumplir con la condición, etc.) para no poder avanzar y, finalmente, pasar hambre o colgar el programa.
Por el contrario, notifyAll () permite que todos los subprocesos en espera vuelvan a adquirir el bloqueo y verifiquen su estado respectivo, lo que finalmente permitirá el progreso.
Por lo tanto, notify () se puede usar de forma segura solo si se garantiza que cualquier subproceso en espera permita avanzar si se selecciona, lo que en general se satisface cuando todos los subprocesos dentro del mismo monitor verifican solo una y la misma condición, algo bastante raro caso en aplicaciones del mundo real.
fuente
Cuando llama al wait () del "objeto" (esperando que se obtenga el bloqueo del objeto), internamente esto liberará el bloqueo de ese objeto y ayudará a los otros hilos a bloquear este "objeto", en este escenario habrá más de 1 subproceso en espera del "recurso / objeto" (teniendo en cuenta que los otros subprocesos también emitieron la espera en el mismo objeto anterior y en el camino habrá un subproceso que llenará el recurso / objeto e invoca notify / notifyAll).
Aquí, cuando emite la notificación del mismo objeto (desde el mismo / otro lado del proceso / código), esto liberará un subproceso único bloqueado y en espera (no todos los subprocesos en espera: este subproceso liberado será elegido por JVM Thread El programador y todo el proceso de obtención de bloqueo en el objeto es el mismo que el habitual).
Si solo tiene un hilo que compartirá / trabajará en este objeto, está bien usar solo el método notify () en su implementación de esperar-notificar.
Si se encuentra en una situación en la que más de un hilo lee y escribe sobre recursos / objetos en función de su lógica empresarial, debe ir a notifyAll ()
ahora estoy mirando cómo exactamente la jvm está identificando y rompiendo el hilo de espera cuando emitimos notify () en un objeto ...
fuente
Si bien hay algunas respuestas sólidas arriba, estoy sorprendido por la cantidad de confusiones y malentendidos que he leído. Esto probablemente prueba la idea de que uno debería usar java.util.concurrent tanto como sea posible en lugar de intentar escribir su propio código concurrente roto. Volviendo a la pregunta: para resumir, la mejor práctica hoy es EVITAR notificar () en TODAS las situaciones debido al problema de activación perdido. A cualquiera que no entienda esto no se le debe permitir escribir código de concurrencia de misión crítica. Si le preocupa el problema del pastoreo, una forma segura de lograr despertar un hilo a la vez es: 1. Crear una cola de espera explícita para los hilos en espera; 2. Haga que cada hilo de la cola espere a su predecesor; 3. Haga que cada subproceso llame a notifyAll () cuando haya terminado. O puede usar Java.util.concurrent. *,
fuente
Runnable
implementación) procesa el contenido de una cola. Lawait()
continuación, se utiliza cada vez que la cola está vacía. Ynotify()
se llama cuando se agrega información. -> en tal caso, solo hay 1 hilo que alguna vez llama alwait()
, entonces no parece un poco tonto usar unnotifyAll()
si sabes que solo hay 1 hilo en espera.Despertar a todos no tiene mucha importancia aquí. espere notifique y notifique a todos, todos estos se colocan después de poseer el monitor del objeto. Si un subproceso está en la etapa de espera y se llama a notificar, este subproceso ocupará el bloqueo y ningún otro subproceso en ese punto puede ocupar ese bloqueo. Por lo tanto, el acceso concurrente no puede tener lugar en absoluto. Hasta donde sé, cualquier llamada para esperar notificar y notificar a todos solo se puede hacer después de bloquear el objeto. Corrígeme si estoy equivocado.
fuente