tipos sincronizados productor modificador metodos evitar ejemplos consumidor concurrencia java multithreading java-me synchronized volatile

sincronizados - tipos de variables en java ejemplos



Diferencia entre volátil y sincronizado en Java (4)

volátil es un modificador de campo , mientras que sincronizado modifica los bloques y métodos de código . Entonces podemos especificar tres variaciones de un descriptor de acceso simple utilizando esas dos palabras clave:

int i1; int geti1() {return i1;} volatile int i2; int geti2() {return i2;} int i3; synchronized int geti3() {return i3;}

geti1() accede al valor actualmente almacenado en i1 en el hilo actual. Los hilos pueden tener copias locales de variables, y los datos no tienen que ser los mismos que los datos contenidos en otros hilos. En particular, otro hilo puede haber actualizado i1 en su hilo, pero el valor en el hilo actual podría ser diferente de ese valor actualizado. De hecho, Java tiene la idea de una memoria "principal", y esta es la memoria que contiene el valor "correcto" actual para las variables. Los subprocesos pueden tener su propia copia de datos para las variables, y la copia del subproceso puede ser diferente de la memoria "principal". Entonces, de hecho, es posible que la memoria "principal" tenga un valor de 1 para i1 , para que thread1 tenga un valor de 2 para i1 y para thread2 para que tenga un valor de 3 para i1 si thread1 e thread2 tienen ambos actualizados i1 pero esos valores actualizados aún no se han propagado a la memoria "principal" u otros hilos.

Por otro lado, geti2() accede efectivamente al valor de i2 desde la memoria "principal". No se permite que una variable volátil tenga una copia local de una variable que sea diferente del valor actualmente almacenado en la memoria "principal". Efectivamente, una variable declarada volátil debe tener sus datos sincronizados en todos los subprocesos, de modo que siempre que acceda o actualice la variable en cualquier subproceso, todos los demás subprocesos vean inmediatamente el mismo valor. Las variables generalmente volátiles tienen una mayor sobrecarga de acceso y actualización que las variables "simples". Generalmente, los hilos tienen su propia copia de datos para una mejor eficacia.

Hay dos diferencias entre volitivo y sincronizado.

Primero sincronizado obtiene y libera bloqueos en monitores que pueden forzar solo un hilo a la vez para ejecutar un bloque de código. Ese es el aspecto bastante conocido para sincronizar. Pero sincronizado también sincroniza la memoria. De hecho sincronizado sincroniza toda la memoria del hilo con la memoria "principal". Entonces, ejecutando geti3() hace lo siguiente:

  1. El hilo adquiere el bloqueo en el monitor para este objeto.
  2. La memoria de hilo vacía todas sus variables, es decir, tiene todas sus variables efectivamente leídas desde la memoria "principal".
  3. El bloque de código se ejecuta (en este caso, se establece el valor de retorno en el valor actual de i3, que puede haberse reiniciado desde la memoria "principal").
  4. (Cualquier cambio en las variables normalmente se escribiría en la memoria "principal", pero para geti3 () no tenemos cambios).
  5. El hilo libera el bloqueo en el monitor para este objeto.

Entonces, cuando volátil solo sincroniza el valor de una variable entre la memoria de hilo y la memoria "principal", sincronización sincroniza el valor de todas las variables entre la memoria de hilo y la memoria "principal", y bloquea y libera un monitor para arrancar. Claramente sincronizado es probable que tenga más sobrecarga que volátil.

http://javaexp.blogspot.com/2007/12/difference-between-volatile-and.html

Me pregunto cuál es la diferencia entre declarar una variable como volatile y acceder siempre a la variable en un bloque synchronized(this) en Java.

De acuerdo con este artículo http://www.javamex.com/tutorials/synchronization_volatile.shtml hay mucho que decir y hay muchas diferencias, pero también algunas similitudes.

Estoy particularmente interesado en esta información:

...

  • el acceso a una variable volátil nunca tiene el potencial de bloqueo: solo hacemos una simple lectura o escritura, por lo que a diferencia de un bloque sincronizado, nunca nos aferraremos a ningún bloqueo;
  • porque acceder a una variable volátil nunca tiene un bloqueo, no es adecuado para casos en los que queremos leer-actualizar-escribir como una operación atómica (a menos que estemos preparados para "perder una actualización");

¿Qué quieren decir con read-update-write ? ¿No es una escritura también una actualización o simplemente significan que la actualización es una escritura que depende de la lectura?

Sobre todo, ¿cuándo es más adecuado declarar variables volatile lugar de acceder a ellas a través de un bloque synchronized ? ¿Es una buena idea usar volatile para las variables que dependen de la entrada? Por ejemplo, ¿hay una variable llamada render que se lee a través del bucle de representación y se establece mediante un evento de pulsación de tecla?


  1. volatile palabra clave volatile en java es un modificador de campo, mientras que la synchronized modifica los bloques de código y los métodos.

  2. synchronized obtiene y libera el bloqueo en la palabra clave volatile java del monitor no lo requiere.

  3. Los subprocesos en Java se pueden bloquear para esperar cualquier monitor en caso de synchronized , ese no es el caso con la palabra clave volatile en Java.

  4. synchronized método synchronized afecta el rendimiento más que la palabra clave volatile en Java.

  5. Dado que la palabra clave volatile en Java solo sincroniza el valor de una variable entre la memoria del hilo y la memoria "principal" mientras que synchronized palabra clave sincronizada sincroniza el valor de todas las variables entre la memoria del hilo y la memoria "principal" y bloquea y libera un monitor para arrancar. Debido a esta razón, es probable que la palabra clave synchronized en Java tenga más sobrecarga que volatile .

  6. No puede sincronizar en un objeto nulo, pero su variable volatile en Java podría ser nula.

  7. Desde Java 5 Escribir en un campo volatile tiene el mismo efecto de memoria que un lanzamiento de monitor, y la lectura desde un campo volátil tiene el mismo efecto de memoria que un monitor adquirido


Es importante comprender que hay dos aspectos para la seguridad del hilo: (1) control de ejecución y (2) visibilidad de la memoria. El primero tiene que ver con controlar cuándo se ejecuta el código (incluido el orden en que se ejecutan las instrucciones) y si se puede ejecutar simultáneamente, y el segundo con cuándo los efectos en la memoria de lo que se ha hecho son visibles para otros hilos. Debido a que cada CPU tiene varios niveles de caché entre ella y la memoria principal, los hilos que se ejecutan en diferentes CPU o núcleos pueden ver la "memoria" de forma diferente en un momento dado porque los subprocesos pueden obtener y trabajar en copias privadas de la memoria principal.

El uso synchronized evita que cualquier otro hilo obtenga el monitor (o bloqueo) para el mismo objeto , impidiendo así que todos los bloques de código protegidos por la sincronización en el mismo objeto se ejecuten simultáneamente. La sincronización también crea una barrera de memoria "pasa antes que", provocando una restricción de visibilidad de memoria tal que cualquier cosa hecha hasta el punto en que un hilo libera un bloqueo aparece en otro hilo adquiriendo posteriormente el mismo bloqueo que había sucedido antes de que adquiriera el bloqueo. En términos prácticos, en el hardware actual, esto normalmente provoca el enjuague de las memorias caché de la CPU cuando se adquiere un monitor y escribe en la memoria principal cuando se lanza, ambas son (relativamente) costosas.

El uso de volatile , por otro lado, obliga a todos los accesos (de lectura o escritura) a la variable volátil a producirse en la memoria principal, manteniendo efectivamente la variable volátil fuera de los cachés de la CPU. Esto puede ser útil para algunas acciones donde simplemente se requiere que la visibilidad de la variable sea correcta y el orden de los accesos no sea importante. El uso de volatile también cambia el tratamiento de long y double para exigir que los accesos sean atómicos; en algunos hardware (antiguos) esto podría requerir bloqueos, aunque no en hardware moderno de 64 bits. Bajo el nuevo modelo de memoria (JSR-133) para Java 5+, la semántica de volátiles se ha fortalecido para que sea casi tan fuerte como sincronizada con respecto a la visibilidad de la memoria y el orden de instrucciones (ver http://www.cs.umd.edu/users/pugh/java/memoryModel/jsr-133-faq.html#volatile ). Para fines de visibilidad, cada acceso a un campo volátil actúa como media sincronización.

Bajo el nuevo modelo de memoria, sigue siendo cierto que las variables volátiles no se pueden reordenar entre sí. La diferencia es que ahora ya no es tan fácil reordenar los accesos de campo normales a su alrededor. Escribir en un campo volátil tiene el mismo efecto de memoria que una versión de monitor, y la lectura desde un campo volátil tiene el mismo efecto de memoria que la adquisición de un monitor. En efecto, debido a que el nuevo modelo de memoria impone restricciones más estrictas al reordenamiento de los accesos de campo volátiles con otros accesos de campo, volátiles o no, todo lo que era visible para el hilo A cuando se escribe en el campo volátil f vuelve visible al hilo B cuando lee f .

- Preguntas frecuentes sobre JSR 133 (Modelo de memoria Java)

Entonces, ahora ambas formas de barrera de memoria (bajo el JMM actual) causan una barrera de reordenamiento de instrucciones que evita que el compilador o el tiempo de ejecución reordenen las instrucciones a través de la barrera. En el antiguo JMM, volátil no impedía reordenar. Esto puede ser importante, porque aparte de las barreras de memoria, la única limitación impuesta es que, para cualquier hilo en particular , el efecto neto del código es el mismo que el que tendría si las instrucciones se ejecutaran exactamente en el orden en que aparecen en el fuente.

Un uso de volátil es para un objeto compartido pero inmutable que se recrea sobre la marcha, con muchos otros hilos que hacen referencia al objeto en un punto particular de su ciclo de ejecución. Uno necesita los otros subprocesos para comenzar a utilizar el objeto recreado una vez que se publica, pero no necesita la sobrecarga adicional de la sincronización completa y su contención concomitante y la limpieza del caché.

// Declaration public class SharedLocation { static public SomeObject someObject=new SomeObject(); // default object } // Publishing code // Note: do not simply use SharedLocation.someObject.xxx(), since although // someObject will be internally consistent for xxx(), a subsequent // call to yyy() might be inconsistent with xxx() if the object was // replaced in between calls. SharedLocation.someObject=new SomeObject(...); // new object is published // Using code private String getError() { SomeObject myCopy=SharedLocation.someObject; // gets current copy ... int cod=myCopy.getErrorCode(); String txt=myCopy.getErrorText(); return (cod+" - "+txt); } // And so on, with myCopy always in a consistent state within and across calls // Eventually we will return to the code that gets the current SomeObject.

Hablando con su pregunta de lectura-actualización-escritura, específicamente. Considere el siguiente código inseguro:

public void updateCounter() { if(counter==1000) { counter=0; } else { counter++; } }

Ahora, con el método updateCounter () no sincronizado, dos hilos pueden ingresar al mismo tiempo. Entre las muchas permutaciones de lo que podría suceder, una es que thread-1 hace la prueba para counter == 1000 y la encuentra verdadera y luego se suspende. Entonces thread-2 hace la misma prueba y también ve que es verdad y está suspendida. Luego, el hilo 1 se reanuda y establece el contador en 0. Luego el hilo 2 se reanuda y nuevamente establece el contador en 0 porque perdió la actualización del hilo 1. Esto también puede suceder incluso si no se produce el cambio de subprocesos como lo he descrito, sino simplemente porque dos copias de contador diferentes almacenadas en caché estaban presentes en dos núcleos de CPU diferentes y cada subproceso se ejecutaba en un núcleo separado. Para ese asunto, un hilo podría tener contador en un valor y el otro podría tener contador en algún valor completamente diferente solo por el almacenamiento en caché.

Lo que es importante en este ejemplo es que el contador de variables se leyó en la memoria principal en caché, se actualizó en caché y solo se volvió a escribir en la memoria principal en algún momento indeterminado cuando se produjo una barrera de memoria o cuando se necesitó memoria caché para otra cosa. Hacer que el contador sea volatile es insuficiente para la seguridad de la hebra de este código, ya que la prueba para el máximo y las asignaciones son operaciones discretas, incluido el incremento que es un conjunto de instrucciones no atómicas de read+increment+write máquina de read+increment+write , como:

MOV EAX,counter INC EAX MOV counter,EAX

Las variables volátiles son útiles solo cuando todas las operaciones que se realizan en ellas son "atómicas", como mi ejemplo en el que una referencia a un objeto completamente formado solo se lee o escribe (y, de hecho, típicamente solo se escribe desde un solo punto). Otro ejemplo sería una referencia de matriz volátil respaldando una lista de copia sobre escritura, siempre que la matriz solo fuera leída tomando primero una copia local de la referencia a la misma.


synchronized es el modificador de restricción de acceso a nivel de nivel / nivel de método. Se asegurará de que un hilo posea el bloqueo para la sección crítica. Solo el hilo, que posee un bloqueo, puede ingresar al bloque synchronized . Si otros subprocesos intentan acceder a esta sección crítica, deben esperar hasta que el propietario actual libere el bloqueo.

volatile es un modificador de acceso variable que obliga a todos los hilos a obtener el último valor de la variable de la memoria principal. No se requiere bloqueo para acceder a volatile variables volatile . Todos los subprocesos pueden acceder al valor de variable volátil al mismo tiempo.

Un buen ejemplo para usar variable volátil: variable de Date .

Supongamos que ha hecho que la variable Fecha sea volatile . Todos los hilos, que acceden a esta variable, siempre obtienen los últimos datos de la memoria principal para que todos los hilos muestren un valor de fecha real (real). No necesita hilos diferentes que muestren una hora diferente para la misma variable. Todos los hilos deberían mostrar el valor de Fecha correcto.

Eche un vistazo a este article para una mejor comprensión del concepto volatile .

Lawrence Dolley explicó su read-write-update query .

En cuanto a sus otras consultas

¿Cuándo es más adecuado declarar las variables volátiles que acceder a ellas de forma sincronizada?

Debes usar volatile si crees que todos los hilos deberían obtener el valor real de la variable en tiempo real, como el ejemplo que he explicado para la variable Fecha.

¿Es una buena idea usar volatilidad para las variables que dependen de la entrada?

La respuesta será la misma que en la primera consulta.

Consulte este article para una mejor comprensión.