threads thread practice example java concurrency

practice - thread java



Modelo de memoria Java: ¿alguien puede explicarlo? (8)

No trataré de explicar estos temas aquí, sino que lo remitiré al excelente libro de Brian Goetz sobre el tema.

El libro es "Concurrencia de Java en la práctica", se puede encontrar en Amazon o en cualquier otra tienda bien ordenada para literatura informática.

Durante años y años, traté de comprender la parte de la especificación de Java que trata sobre el modelo de memoria y la concurrencia. Debo admitir que he fallado miserablemente. Sí "Entiendo sobre bloqueos y" sincronizado "y wait () y notify (). Y puedo usarlos bien, gracias. Incluso tengo una vaga idea sobre lo que hace "volátil". Pero todo eso no se derivó de la especificación del lenguaje, sino de la experiencia general.

Aquí hay dos preguntas de muestra que estoy preguntando. No estoy demasiado interesado en respuestas particulares, ya que necesito entender cómo se derivan las respuestas de la especificación (o puedo concluir que la especificación no tiene respuesta).

  • ¿Qué hace "volátil", exactamente?
  • ¿Se escribe en variable atómica? ¿Depende del tipo de variable?

No voy a intentar responder sus preguntas aquí, sino que lo redirigiré al libro que he recomendado para obtener asesoramiento sobre este tema: Java Concurrency in Practice .

Una palabra de advertencia: si hay respuestas aquí, espera que algunas de ellas estén equivocadas. Una de las razones por las que no voy a publicar detalles es porque estoy bastante seguro de que me equivocaré al menos en algunos aspectos. Me refiero sin falta de respeto a la comunidad cuando digo que las posibilidades de que todos los que piensan que pueden responder a esta pregunta con el rigor suficiente para hacerlo bien son prácticamente nulas. (Joe Duffy recientemente encontró un poco del modelo de memoria .NET que fue sorprendido por. Si él puede equivocarse, también lo hacen los mortales como nosotros).

Ofreceré algunas ideas sobre un solo aspecto, porque a menudo se malinterpreta:

Hay una diferencia entre volatilidad y atomicidad. La gente a menudo piensa que una escritura atómica es volátil (es decir, no necesita preocuparse por el modelo de memoria si la escritura es atómica). Eso no es cierto.

La volatilidad se trata de si un hilo que realiza una lectura (lógicamente, en el código fuente) "verá" los cambios realizados por otro hilo.

La atomicidad se trata de si hay alguna posibilidad de que si se ve un cambio, solo se vea parte del cambio.

Por ejemplo, tome escribir en un campo entero. Eso se garantiza que es atómico, pero no volátil. Eso significa que si tenemos (comenzando en foo.x = 0):

Thread 1: foo.x = 257; Thread 2: int y = foo.x;

Es posible que y sea ​​0 o 257. No tendrá ningún otro valor, (por ejemplo, 256 o 1) debido a la restricción de atomicidad. Sin embargo, incluso si sabes que en "tiempo de pared" el código en el hilo 2 ejecutado después del código en el hilo 1, podría haber un caché extraño, acceso a memoria "moviéndose", etc. Hacer que la variable x volátil lo arreglará.

Dejo el resto en manos de verdaderos expertos en honestidad.


Una noción podría ser útil: datos (dato) y copias.

Si declara una variable, digamos un byte, reside en algún lugar de la memoria, en un segmento de datos (aproximadamente hablando). Hay 8 bits en algún lugar de la memoria dedicados a almacenar esa información.

Sin embargo, puede haber varias copias de esos datos, moviéndose en su máquina. Por diversos motivos técnicos, por ejemplo, el almacenamiento local del hilo, las optimizaciones del compilador. Y si tenemos varias copias, es posible que no estén sincronizadas.

Entonces, siempre debes tener en cuenta esta idea. Es cierto no solo para los campos de la clase java, sino también para las variables cpp, los registros de la base de datos (los datos del estado del registro se copian en varias sesiones, etc.). Las variables, sus copias ocultas / visibles y los sutiles problemas de sincronización estarán por siempre.



  • volatile variables no volatile pueden almacenarse en caché localmente, de modo que diferentes hilos pueden ver valores diferentes al mismo tiempo; volatile evita esto ( fuente )
  • escribe en variables de 32 bits o menos que se garantiza que son atómicas ( implícitas aquí ); no es así por long y el double , aunque las JVM de 64 bits probablemente las implementen como operaciones atómicas

Otras respuestas anteriores son absolutamente correctas en el sentido de que su pregunta no es para el amago de corazón.

Sin embargo, entiendo tu dolor por realmente querer obtener lo que está bajo el capó, para esto te diría de vuelta a los compiladores de mundos y predecesores de bajo nivel a java, es decir, ensamblado, C y C ++.

Lea sobre diferentes tipos de barreras (''vallas''). Comprender qué es una barrera de la memoria y dónde es necesaria le ayudará a tener una comprensión intuitiva de lo que es volátil.


Otro intento de proporcionar un resumen de las cosas que entendí de las respuestas aquí y de otras fuentes (el primer intento estaba muy lejos de la base. Espero que este sea mejor).

El modelo de memoria Java se trata de propagar los valores escritos en la memoria en un subproceso a otros subprocesos para que otros subprocesos puedan verlos mientras leen desde la memoria.

En resumen, si obtiene un bloqueo en un mutex, cualquier cosa escrita por cualquier hilo que haya liberado ese mutex antes será visible para su hilo.

Si lee una variable volátil, cualquier cosa escrita en esa variable volátil antes de leerla es visible para el hilo de lectura. Además, cualquier escritura en la variable volátil realizada por el hilo que escribe en su variable antes de que la escritura en su variable sea visible. Por otra parte, en Java 1.5 cualquier escritura, volátil o no, que sucedió en cualquier hilo que escribió a su variable volátil antes de que la escritura a su variable volátil será visible para usted.

Después de construir un objeto, puede pasarlo a otro hilo, y todos los miembros finales serán visibles y estarán completamente construidos en el nuevo hilo. No hay garantías similares sobre los miembros no finales. Eso me hace pensar que la asignación a un miembro final actúa como una variable de escritura en la variable volátil (valla de memoria).

Cualquier cosa que un hilo haya escrito antes de que se haya ejecutado Runnable es visible para el hilo que ejecuta join (). Cualquier cosa que un hilo haya escrito antes de ejecutar start () será visible para el hilo generado.

Otra cosa para mencionar: las variables volátiles y la sincronización tienen una función que rara vez se menciona: además de enjuagar la memoria caché de hilos y proporcionar acceso de un solo hilo a la vez, también evitan que el compilador y la CPU reordenen lecturas y escrituras a lo largo del límite de sincronización.

Nada de esto es nuevo y las otras respuestas lo han expresado mejor. Solo quería escribir esto para aclarar mi mente.


Recientemente encontré un excelente artículo que explica la volatilidad como:

Primero, debes entender algo sobre el modelo de memoria de Java. He luchado un poco a lo largo de los años para explicarlo brevemente y bien. A partir de hoy, la mejor manera en que puedo pensar para describirlo es si lo imaginas de esta manera:

  • Cada hilo en Java tiene lugar en un espacio de memoria separado (esto es claramente falso, así que tengan paciencia conmigo en este caso).

  • Debe usar mecanismos especiales para garantizar que la comunicación se realice entre estos hilos, como lo haría en un sistema de transmisión de mensajes.

  • Las escrituras de memoria que suceden en un hilo pueden "filtrarse" y ser vistas por otro hilo, pero esto de ninguna manera está garantizado. Sin comunicación explícita, no puede garantizar qué escrituras son vistas por otros hilos, o incluso el orden en el que se ven.

El modificador volátil de Java es un ejemplo de un mecanismo especial para garantizar que la comunicación se realice entre hilos. Cuando un hilo escribe en una variable volátil, y otro hilo ve esa escritura, el primer hilo le dice al segundo sobre todos los contenidos de la memoria hasta que realiza la escritura en esa variable volátil.

Enlaces adicionales: http://jeremymanson.blogspot.com/2008/11/what-volatile-means-in-java.html http://www.javaperformancetuning.com/news/qotm030.shtml