Boolean volátil vs AtomicBoolean

244

¿Qué hace AtomicBoolean que un booleano volátil no puede lograr?

JeffV
fuente
16
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.
JeffV
1
posible duplicado de booleano volátil vs. AtomicBoolean
Flujo
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.
Sactiw

Respuestas:

99

Son simplemente totalmente diferentes. Considere este ejemplo de un volatileentero:

volatile int 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

volatile boolean stop = false;
void loop() {
    while (!stop) { ... }
}
void stop() { stop = true; }

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.

Cefalópodo
fuente
84
-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)

teto
fuente
1
@ksl Creo que @teto quiere describir que si solo un hilo modifica la booleanvar, deberíamos elegir volatile boolean.
znlyj
2
Excelente resumen
Ravindra babu
56

No puede hacerlo compareAndSet, getAndSetcomo operación atómica con booleano volátil (a menos que, por supuesto, lo sincronice).

nanda
fuente
66
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;
    return true;
} else {
    return false;
}

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:

final AtomicBoolean isJobDone = new AtomicBoolean(false);

...

if (isJobDone.compareAndSet(false, true)) {
    listener.notifyJobDone();
}

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).

Nam San
fuente
14

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.

dhblah
fuente
14
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:

public class AtomicLong extends Number implements java.io.Serializable {
   ...
   private volatile long value;
   ...
   public final long get() {
       return value;
   }
   ...
   public final void 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.

private volatile value;
...
// race conditions here
value++;

Sin embargo, el siguiente código funcionará en un entorno multiproceso de forma segura sin bloqueos:

private final AtomicLong value = new AtomicLong();
...
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.

gris
fuente
5

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.

Amol Gaikwad
fuente
4

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.

usuario2660000
fuente
3

Recuerda la IDIOMA

LEER - MODIFICAR- ESCRIBIR esto no se puede lograr con volátil

Muévete rápido
fuente
2
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:

  1. El valor booleano es leído.
  2. 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.

Thibaut D.
fuente
-1

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.

Bismaya Mohapatra
fuente