Pregunta

He implementado un perfilador simple con JVMTI para mostrar la invocación en wait() y notifyAll(). Como caso de prueba, estoy usando el. Ejemplo de consumidor de productor de Oracle. Tengo los siguientes tres eventos:

  • NotifyAll () se invoca
  • esperar () se invoca
  • esperar () queda

los wait() invocación y cuando lo dejó perfilado usando los eventos MonitorEnter y MonitorExit. los notifyAll() La invocación se perfila cuando un método con nombre notifyAll está saliendo.

Ahora tengo los siguientes resultados, el Primero es del Profiler en sí y el El segundo es de Java, donde he colocado el apropiado System.out.println declaración.

    // Profiler:
    Thread-1 invoked notifyAll()
    Thread-0 invoked notifyAll()
    Thread-0 invoked notifyAll()
    Thread-0 invoked notifyAll()
    Thread-0 invoked notifyAll()
    Thread-0 invoked notifyAll()
    Thread-1 invoked notifyAll()
    Thread-1 invoked notifyAll()
    Thread-1 invoked notifyAll()
    Thread-1 invoked notifyAll()
    Thread-1 invoked notifyAll()
    Thread-1 invoked notifyAll()
    Thread-1 invoked notifyAll()
    Thread-1 invoked wait()
    Thread-1 left wait()
    Thread-1 invoked notifyAll()
    Thread-1 invoked wait()
    Thread-1 left wait()
    Thread-1 invoked notifyAll()
    Thread-1 invoked wait()
    Thread-1 left wait()
    Thread-1 invoked notifyAll()

    // Java:
    Thread-0 invoked notifyAll()
    Thread-1 invoked notifyAll()
    Thread-0 invoked notifyAll()
    Thread-1 invoked notifyAll()
    Thread-0 invoked notifyAll()
    Thread-1 invoked wait()
    Thread-1 invoked notifyAll()
    Thread-0 invoked notifyAll()
    Thread-1 invoked wait()
    Thread-1 invoked notifyAll()
    Thread-0 invoked notifyAll()
    Thread-1 invoked wait()
    Thread-1 invoked notifyAll()

¿Tiene alguien una explicación de lo que proviene esta discrepancia? notifyAll() se llama tantas veces. Me dijeron que esto podría deberse a respuestas falsas positivas de la solicitud de Java al sistema operativo.

A notifyAll() Solicite que envíe al sistema operativo y se envía una respuesta falsa positiva, donde parece que la solicitud fue exitosa. Ya que notifyAll se registra mediante invocación del método de perfil en lugar de MonitorEnter Podría explicar por qué esto no sucede con Wait.

Olvidé decir que no ejecuté los programas por separado, ambos registros son de la misma ejecución.

Información adicional

Originalmente agregado como respuesta, movido a la pregunta por extraaneon:

Creo que descubrí donde alguno De los notificados adicionales provienen, agregué el perfil del contexto del método en el que se llama notificar todo:

723519: Thread-1 invoked notifyAll() in Consumer.take
3763279: Thread-0 invoked notifyAll() in Producer.put
4799016: Thread-0 invoked notifyAll() in Producer.put
6744322: Thread-0 invoked notifyAll() in Producer.put
8450221: Thread-0 invoked notifyAll() in Producer.put
10108959: Thread-0 invoked notifyAll() in Producer.put
39278140: Thread-1 invoked notifyAll() in java.util.ResourceBundle.endLoading
40725024: Thread-1 invoked notifyAll() in java.util.ResourceBundle.endLoading
42003869: Thread-1 invoked notifyAll() in java.util.ResourceBundle.endLoading
58448450: Thread-1 invoked notifyAll() in java.util.ResourceBundle.endLoading
60236308: Thread-1 invoked notifyAll() in java.util.ResourceBundle.endLoading
61601587: Thread-1 invoked notifyAll() in java.util.ResourceBundle.endLoading
70489811: Thread-1 invoked notifyAll() in Consumer.take
75068409: Thread-1 invoked wait() in Drop.take
75726202: Thread-1 left wait() in Drop.take
77035733: Thread-1 invoked notifyAll() in Consumer.take
81264978: Thread-1 invoked notifyAll() in Consumer.take
85810491: Thread-1 invoked wait() in Drop.take
86477385: Thread-1 left wait() in Drop.take
87775126: Thread-1 invoked notifyAll() in Consumer.take

Pero incluso sin estas llamadas externas, existen llamadas de notificación que no aparecen en la depuración de printf.

¿Fue útil?

Solución

Pasé un tiempo analizando el Productor-consumidor Ejemplo proporcionado por Oracle y su salida (Profiler y Java Program). Hay algunas cosas extrañas en sus salidas además de los varios inesperados notifyAll():

  1. Deberíamos esperar que el método Wait () se ejecute 4 veces (el String La matriz manipulada por el productor tiene 4 elementos). El resultado de su Profiler muestra que solo se ejecutó tres veces.

  2. Otra cosa que es bastante extraña es la numeración de los hilos en la salida del perfilador. El ejemplo tiene dos hilos, sin embargo, su perfilador ejecuta todo el código en un hilo, es decir Thread-1, tiempo Thread-0 Solo ejecuta notifyAll().

  3. El código de ejemplo proporcionado se programa correctamente desde una perspectiva concurrente y una perspectiva del lenguaje: wait() y notifyAll() están en métodos sincronizados para garantizar el control sobre el monitor; La condición de espera está dentro de un while Encaje con las notificaciones colocadas correctamente en el final de los métodos. Sin embargo, noté que el catch (InterruptedException e) El bloque está vacío, lo que significa que si el hilo que está esperando se interrumpe, el notifyAll() Se ejecutará el método. Esto puede ser una causa de los varios inesperados notifyAll().

En conclusión, sin realizar algunas modificaciones en el código y realizar algunas pruebas adicionales, no será fácil averiguar de dónde proviene el problema.

Como nota al margen, dejaré este enlace Creación de un agente de depuración y perfil con JVMTI para los curiosos que quieren jugar con JVMTI.

Otros consejos

Si tiene una condición de carrera en su código, un perfilador puede ralentizar el código lo suficiente como para mostrar u ocultar un error en su código. (Me gusta dirigir mi programa en un perfilador, solo para mostrar condiciones de carrera).

Como notifyall () solo notificará a los hilos de espera (), llamando a Wait () después de que el notifyall () es probable que produzca la falta de notificación. es decir, es apátrate, no sabe que llamó a notificar antes.

Si ralentiza su aplicación, el notifyAll () se puede retrasar hasta que comience la espera ().

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top