Estaba buscando una respuesta más matizada a: "¿cuáles son las limitaciones de cada uno?". Por ejemplo, si is es una bandera establecida por un hilo y leída por uno o más, no es necesario AtomicBoolean. Sin embargo, como estoy viendo con estas respuestas, si los subprocesos que comparten una variable en varios subprocesos pueden escribir y están actuando sobre el resultado de sus lecturas, AtomicBoolean pone en juego operaciones sin bloqueo de tipo CAS. Estoy aprendiendo bastante aquí, en realidad. Con suerte, otros también se beneficiarán.
el booleano volátil necesitará una sincronización explícita para manejar las condiciones de carrera, en otras palabras, un escenario como el recurso compartido que se actualiza (cambio de estado) por múltiples subprocesos, por ejemplo, contador de incremento / decremento o volteo booleano.
Son simplemente totalmente diferentes. Considere este ejemplo de un volatileentero:
volatileint i =0;void incIBy5(){
i +=5;}
Si dos hilos llaman a la función simultáneamente, ipuede ser 5 después, ya que el código compilado será algo similar a esto (excepto que no se puede sincronizar int):
void incIBy5(){int temp;synchronized(i){ temp = i }synchronized(i){ i = temp +5}}
Si una variable es volátil, cada acceso atómico está sincronizado, pero no siempre es obvio lo que realmente califica como acceso atómico. Con un Atomic*objeto, se garantiza que cada método es "atómico".
Por lo tanto, si usa un AtomicIntegery getAndAdd(int delta), puede estar seguro de que el resultado será 10. De la misma manera, si dos subprocesos niegan una booleanvariable al mismo tiempo, con un AtomicBooleanpuede estar seguro de que tiene el valor original después, con un volatile boolean, no puede.
Por lo tanto, siempre que tenga más de un hilo modificando un campo, debe hacerlo atómico o usar sincronización explícita.
El propósito de volatilees diferente. Considera este ejemplo
Si tiene un subproceso ejecutándose loop()y otro subproceso llamando stop(), podría omitir un bucle infinito si omite volatile, ya que el primer subproceso podría almacenar en caché el valor de stop. Aquí, volatilesirve como una pista para que el compilador sea un poco más cuidadoso con las optimizaciones.
-1: estás dando ejemplos pero realmente no explicas la diferencia entre un volátil y un Atomicxxxx.
Jason S
70
La pregunta no es sobre volatile. La pregunta es acerca volatile booleanvs AtomicBoolean.
dolmen
26
-1: la pregunta formulada específicamente sobre booleano, que es un caso único en comparación con los otros tipos de datos y debe explicarse directamente.
John Haager
8
@ sgp15 Tiene que ver con la sincronización a partir de Java 5.
Man of One Way
66
Si el valor booleano es leído por muchos hilos, pero escrito por un solo hilo, entonces volatile booleanes suficiente. Si también hay muchos escritores, es posible que lo necesite AtomicBoolean.
StvnBrkdll
263
Utilizo campos volátiles cuando dicho campo SÓLO ES ACTUALIZADO por su hilo propietario y el valor solo lo leen otros hilos, puede pensarlo como un escenario de publicación / suscripción donde hay muchos observadores pero solo un editor. Sin embargo, si esos observadores deben realizar alguna lógica basada en el valor del campo y luego retroceder un nuevo valor, entonces voy con Atomic * vars o bloqueos o bloques sincronizados, lo que mejor me convenga. En muchos escenarios concurrentes, se reduce a obtener el valor, compararlo con otro y actualizar si es necesario, de ahí los métodos compareAndSet y getAndSet presentes en las clases Atomic *.
Consulte los JavaDocs del paquete java.util.concurrent.atomic para obtener una lista de clases atómicas y una excelente explicación de cómo funcionan (acabo de enterarme de que no tienen bloqueos, por lo que tienen una ventaja sobre los bloqueos o bloques sincronizados)
Esto es cierto, pero ¿no sería un requisito bastante raro para un booleano?
Robin
1
@Robin piensa en usarlo para controlar una invocación diferida de un método de inicialización.
Ustaman Sangat el
En realidad, creo que este es uno de los principales casos de uso.
fool4jesus
42
AtomicBooleantiene métodos que realizan sus operaciones compuestas atómicamente y sin tener que usar un synchronizedbloque. Por otro lado, volatile booleansolo puede realizar operaciones compuestas si lo hace dentro de un synchronizedbloque.
Los efectos de memoria de lectura / escritura volatile booleanson idénticos a los métodos gety setde AtomicBooleanrespectivamente.
Por ejemplo, el compareAndSetmétodo realizará atómicamente lo siguiente (sin synchronizedbloque):
if(value == expectedValue){
value = newValue;returntrue;}else{returnfalse;}
Por lo tanto, el compareAndSetmétodo le permitirá escribir código que se garantiza que se ejecutará solo una vez, incluso cuando se lo llame desde varios subprocesos. Por ejemplo:
Se garantiza que solo notificará al oyente una vez (suponiendo que ningún otro subproceso establezca la parte AtomicBooleanposterior falsenuevamente después de que se configure en true).
volatileLa palabra clave garantiza la relación de suceso previo entre hilos que comparten esa variable No garantiza que 2 o más subprocesos no se interrumpan entre sí al acceder a esa variable booleana.
El acceso booleano (como en el tipo primitivo) es atómico en Java. Ambas lecturas y tareas. Por lo tanto, ningún otro hilo "interrumpirá" las operaciones booleanas.
Maciej Biłas
1
Lo siento, pero ¿cómo responde esto a la pregunta? Una Atomic*clase envuelve un volatilecampo.
Grey
¿No son los cachés de la CPU el factor principal para configurar volátiles? Para asegurarse de que el valor leído es en realidad lo que se estableció más recientemente
Jocull
8
Boolean volátil vs AtomicBoolean
Las clases Atomic * envuelven una primitiva volátil del mismo tipo. De la fuente:
publicclassAtomicLongextendsNumberimplements java.io.Serializable{...privatevolatilelong value;...publicfinallong get(){return value;}...publicfinalvoid set(long newValue){
value = newValue;}
Entonces, si todo lo que está haciendo es obtener y configurar un Atomic *, entonces también podría tener un campo volátil.
¿Qué hace AtomicBoolean que un booleano volátil no puede lograr?
Las clases Atomic * le brindan métodos que proporcionan una funcionalidad más avanzada, como incrementAndGet(), compareAndSet()y otros que implementan múltiples operaciones (obtener / incrementar / establecer, probar / establecer) sin bloqueo. Es por eso que las clases Atomic * son tan poderosas.
Por ejemplo, si varios subprocesos usan el siguiente código ++, habrá condiciones de carrera porque en ++realidad es: obtener, incrementar y establecer.
privatevolatile value;...// race conditions here
value++;
Sin embargo, el siguiente código funcionará en un entorno multiproceso de forma segura sin bloqueos:
privatefinalAtomicLong value =newAtomicLong();...
value.incrementAndGet();
También es importante tener en cuenta que ajustar su campo volátil con la clase Atomic * es una buena manera de encapsular el recurso crítico compartido desde el punto de vista de un objeto. Esto significa que los desarrolladores no pueden simplemente lidiar con el campo suponiendo que no se comparte, posiblemente inyectando problemas con un campo ++; u otro código que introduzca condiciones de carrera.
Si hay varios subprocesos que acceden a la variable de nivel de clase, cada subproceso puede mantener una copia de esa variable en su caché local de subprocesos.
Hacer que la variable sea volátil evitará que los hilos mantengan la copia de la variable en la caché local de hilos.
Las variables atómicas son diferentes y permiten la modificación atómica de sus valores.
El tipo primitivo booleano es atómico para operaciones de escritura y lectura, volátil garantiza el principio de antes. Entonces, si necesita un simple get () y set (), entonces no necesita el AtomicBoolean.
Por otro lado, si necesita implementar alguna verificación antes de establecer el valor de una variable, por ejemplo, "si es verdadero, entonces se establece en falso", entonces también debe realizar esta operación atómicamente, en este caso, use compareAndSet y otros métodos proporcionados por AtomicBoolean, ya que si intenta implementar esta lógica con boolean volátil, necesitará cierta sincronización para asegurarse de que el valor no haya cambiado entre get y set.
Corto, crujiente y al grano. volatilesolo funciona en los casos en que el subproceso propietario tiene la capacidad de actualizar el valor del campo y los otros subprocesos solo pueden leer.
Chaklader Asfak Arefe
3
Si solo tiene un hilo que modifica su booleano, puede usar un booleano volátil (generalmente lo hace para definir una stopvariable marcada en el bucle principal del hilo).
Sin embargo, si tiene múltiples hilos modificando el booleano, debe usar un AtomicBoolean. De lo contrario, el siguiente código no es seguro:
boolean r =!myVolatileBoolean;
Esta operación se realiza en dos pasos:
El valor booleano es leído.
El valor booleano está escrito.
Si otro hilo modifica el valor entre #1y 2#, es posible que obtenga un resultado incorrecto. AtomicBooleanLos métodos evitan este problema haciendo pasos #1y #2atómicamente.
Ambos son del mismo concepto, pero en booleano atómico proporcionará atomicidad a la operación en caso de que el interruptor de la CPU ocurra en el medio.
Respuestas:
Son simplemente totalmente diferentes. Considere este ejemplo de un
volatile
entero:Si dos hilos llaman a la función simultáneamente,
i
puede ser 5 después, ya que el código compilado será algo similar a esto (excepto que no se puede sincronizarint
):Si una variable es volátil, cada acceso atómico está sincronizado, pero no siempre es obvio lo que realmente califica como acceso atómico. Con un
Atomic*
objeto, se garantiza que cada método es "atómico".Por lo tanto, si usa un
AtomicInteger
ygetAndAdd(int delta)
, puede estar seguro de que el resultado será10
. De la misma manera, si dos subprocesos niegan unaboolean
variable al mismo tiempo, con unAtomicBoolean
puede estar seguro de que tiene el valor original después, con unvolatile boolean
, no puede.Por lo tanto, siempre que tenga más de un hilo modificando un campo, debe hacerlo atómico o usar sincronización explícita.
El propósito de
volatile
es diferente. Considera este ejemploSi tiene un subproceso ejecutándose
loop()
y otro subproceso llamandostop()
, podría omitir un bucle infinito si omitevolatile
, ya que el primer subproceso podría almacenar en caché el valor de stop. Aquí,volatile
sirve como una pista para que el compilador sea un poco más cuidadoso con las optimizaciones.fuente
volatile
. La pregunta es acercavolatile boolean
vsAtomicBoolean
.volatile boolean
es suficiente. Si también hay muchos escritores, es posible que lo necesiteAtomicBoolean
.Utilizo campos volátiles cuando dicho campo SÓLO ES ACTUALIZADO por su hilo propietario y el valor solo lo leen otros hilos, puede pensarlo como un escenario de publicación / suscripción donde hay muchos observadores pero solo un editor. Sin embargo, si esos observadores deben realizar alguna lógica basada en el valor del campo y luego retroceder un nuevo valor, entonces voy con Atomic * vars o bloqueos o bloques sincronizados, lo que mejor me convenga. En muchos escenarios concurrentes, se reduce a obtener el valor, compararlo con otro y actualizar si es necesario, de ahí los métodos compareAndSet y getAndSet presentes en las clases Atomic *.
Consulte los JavaDocs del paquete java.util.concurrent.atomic para obtener una lista de clases atómicas y una excelente explicación de cómo funcionan (acabo de enterarme de que no tienen bloqueos, por lo que tienen una ventaja sobre los bloqueos o bloques sincronizados)
fuente
boolean
var, deberíamos elegirvolatile boolean
.No puede hacerlo
compareAndSet
,getAndSet
como operación atómica con booleano volátil (a menos que, por supuesto, lo sincronice).fuente
AtomicBoolean
tiene métodos que realizan sus operaciones compuestas atómicamente y sin tener que usar unsynchronized
bloque. Por otro lado,volatile boolean
solo puede realizar operaciones compuestas si lo hace dentro de unsynchronized
bloque.Los efectos de memoria de lectura / escritura
volatile boolean
son idénticos a los métodosget
yset
deAtomicBoolean
respectivamente.Por ejemplo, el
compareAndSet
método realizará atómicamente lo siguiente (sinsynchronized
bloque):Por lo tanto, el
compareAndSet
método le permitirá escribir código que se garantiza que se ejecutará solo una vez, incluso cuando se lo llame desde varios subprocesos. Por ejemplo:Se garantiza que solo notificará al oyente una vez (suponiendo que ningún otro subproceso establezca la parte
AtomicBoolean
posteriorfalse
nuevamente después de que se configure entrue
).fuente
volatile
La palabra clave garantiza la relación de suceso previo entre hilos que comparten esa variable No garantiza que 2 o más subprocesos no se interrumpan entre sí al acceder a esa variable booleana.fuente
Atomic*
clase envuelve unvolatile
campo.Las clases Atomic * envuelven una primitiva volátil del mismo tipo. De la fuente:
Entonces, si todo lo que está haciendo es obtener y configurar un Atomic *, entonces también podría tener un campo volátil.
Las clases Atomic * le brindan métodos que proporcionan una funcionalidad más avanzada, como
incrementAndGet()
,compareAndSet()
y otros que implementan múltiples operaciones (obtener / incrementar / establecer, probar / establecer) sin bloqueo. Es por eso que las clases Atomic * son tan poderosas.Por ejemplo, si varios subprocesos usan el siguiente código
++
, habrá condiciones de carrera porque en++
realidad es: obtener, incrementar y establecer.Sin embargo, el siguiente código funcionará en un entorno multiproceso de forma segura sin bloqueos:
También es importante tener en cuenta que ajustar su campo volátil con la clase Atomic * es una buena manera de encapsular el recurso crítico compartido desde el punto de vista de un objeto. Esto significa que los desarrolladores no pueden simplemente lidiar con el campo suponiendo que no se comparte, posiblemente inyectando problemas con un campo ++; u otro código que introduzca condiciones de carrera.
fuente
Si hay varios subprocesos que acceden a la variable de nivel de clase, cada subproceso puede mantener una copia de esa variable en su caché local de subprocesos.
Hacer que la variable sea volátil evitará que los hilos mantengan la copia de la variable en la caché local de hilos.
Las variables atómicas son diferentes y permiten la modificación atómica de sus valores.
fuente
El tipo primitivo booleano es atómico para operaciones de escritura y lectura, volátil garantiza el principio de antes. Entonces, si necesita un simple get () y set (), entonces no necesita el AtomicBoolean.
Por otro lado, si necesita implementar alguna verificación antes de establecer el valor de una variable, por ejemplo, "si es verdadero, entonces se establece en falso", entonces también debe realizar esta operación atómicamente, en este caso, use compareAndSet y otros métodos proporcionados por AtomicBoolean, ya que si intenta implementar esta lógica con boolean volátil, necesitará cierta sincronización para asegurarse de que el valor no haya cambiado entre get y set.
fuente
Recuerda la IDIOMA
LEER - MODIFICAR- ESCRIBIR esto no se puede lograr con volátil
fuente
volatile
solo funciona en los casos en que el subproceso propietario tiene la capacidad de actualizar el valor del campo y los otros subprocesos solo pueden leer.Si solo tiene un hilo que modifica su booleano, puede usar un booleano volátil (generalmente lo hace para definir una
stop
variable marcada en el bucle principal del hilo).Sin embargo, si tiene múltiples hilos modificando el booleano, debe usar un
AtomicBoolean
. De lo contrario, el siguiente código no es seguro:Esta operación se realiza en dos pasos:
Si otro hilo modifica el valor entre
#1
y2#
, es posible que obtenga un resultado incorrecto.AtomicBoolean
Los métodos evitan este problema haciendo pasos#1
y#2
atómicamente.fuente
Ambos son del mismo concepto, pero en booleano atómico proporcionará atomicidad a la operación en caso de que el interruptor de la CPU ocurra en el medio.
fuente