java - settitle - ¿La sincronización vacía(esto){} tiene algún significado para la visibilidad de la memoria entre subprocesos?
para que sirve settitle en java (2)
Lamentablemente, gran parte de lo que está escrito sobre esto, incluyendo muchas de las respuestas / comentarios en este hilo, está mal.
La regla clave en el modelo de memoria Java que se aplica aquí es: una operación de desbloqueo en un monitor determinado ocurre antes de una operación de bloqueo posterior en ese mismo monitor. Si solo un hilo adquiere el bloqueo, no tiene ningún significado. Si la máquina virtual puede probar que el objeto de bloqueo está restringido a subprocesos, puede eliminar cualquier valla que de lo contrario podría emitir.
La cita que resalta asume que liberar un bloqueo actúa como una cerca completa. Y a veces eso puede ser cierto, pero no se puede contar con ello. Así que sus preguntas escépticas están bien fundadas.
Consulte Java concurrencia en la práctica , capítulo 16 para obtener más información sobre el modelo de memoria Java.
Leí esto en un comentario upvoted en StackOverflow:
Pero si desea estar seguro, puede agregar una sincronización simple (esto) {} al final de usted @PostConstruct [método]
[note que las variables NO fueron volátiles]
Estaba pensando que eso sucede: antes es forzado solo si tanto la escritura como la lectura se ejecutan en bloque synchronized
o al menos la lectura es volátil.
¿Es correcta la frase citada? ¿Un bloque synchronized(this) {}
vacío vacía todas las variables cambiadas en el método actual a la memoria "visible en general"?
Por favor considera algunos escenarios
¿Qué pasa si el segundo hilo nunca llama bloqueo en
this
? (Supongamos que el segundo hilo se lee en otros métodos). Recuerde que la pregunta trata sobre: vaciar los cambios en otros subprocesos , no dar a otros subprocesos una forma (sincronizada) de sondear los cambios realizados por el subproceso original . También es muy probable que no haya sincronización en otros métodos en el contexto Spring@PostConstruct
, como dice el comentario original.¿la visibilidad de la memoria de los cambios está forzada solo en la segunda y subsiguientes llamadas por otro hilo? (recuerde que este bloque sincronizado es la última llamada de nuestro método): esto marcaría esta forma de sincronización como una práctica muy mala (valores obsoletos en la primera llamada)
Todas las escrituras que se producen antes de una monitor exit
son visibles para todos los subprocesos después de que monitor enter
un monitor enter
.
Un synchronized(this){}
puede convertirse en un bytecode como
monitorenter
monitorexit
Entonces, si tiene un montón de escrituras antes de la synchronized(this){}
se habrían producido antes del monitorexit
.
Esto nos lleva al siguiente punto de mi primera oración.
visible para todos los hilos después de un
monitor enter
Así que ahora, para que un hilo asegure las escrituras ocurridas, debe ejecutar la misma sincronización, es decir, sincronizado synchornized(this){}
. Esto emitirá por lo menos un monitorenter
y establecerá su suceso antes de ordenar.
Así que para responder a tu pregunta
¿Un bloque sincronizado (esto) {} vacío vacía todas las variables cambiadas en el método actual a la memoria "visible en general"?
Sí, siempre y cuando mantenga la misma sincronización cuando quiera leer esas variables no volátiles.
Para abordar sus otras preguntas
¿Qué pasa si el segundo hilo nunca llama bloqueo en esto? (Supongamos que el segundo hilo se lee en otros métodos). Recuerde que la pregunta trata sobre: vaciar los cambios en otros subprocesos, no dar a otros subprocesos una forma (sincronizada) de sondear los cambios realizados por el subproceso original. También es muy probable que no haya sincronización en otros métodos en el contexto Spring @PostConstruct
Bueno, en este caso el uso synchronized(this)
sin ningún otro contexto es relativamente inútil. No hay una relación antes de que ocurra, y en teoría es tan útil como no incluirla.
¿Es la visibilidad de la memoria de los cambios forzados solo en la segunda y subsiguientes llamadas por otro hilo? (recuerde que este bloque sincronizado es la última llamada de nuestro método): esto marcaría esta forma de sincronización como una práctica muy mala (valores obsoletos en la primera llamada)
La visibilidad de la memoria se ve forzada por el primer subproceso que se synchronized(this)
, ya que se escribirá directamente en la memoria. Ahora, esto no significa necesariamente que cada subproceso deba leer directamente de la memoria. Todavía pueden leer desde sus propios cachés de procesador. Tener una llamada de subproceso synchronized(this)
garantiza que extraiga el valor de los campos de la memoria y recupere el valor más actualizado.