Respuestas:
Cuando múltiples hilos necesitan verificar y cambiar el booleano. Por ejemplo:
if (!initialized) {
initialize();
initialized = true;
}
Esto no es seguro para subprocesos. Puedes arreglarlo usando AtomicBoolean
:
if (atomicInitialized.compareAndSet(false, true)) {
initialize();
}
true
cuando initialize()
no se ha completado. Por lo tanto, funciona solo si otros hilos no se preocupan por completarlos initialize()
.
initialized
simplemente se está utilizando para garantizar que un solo hilo invoque el initialize()
método. Obviamente, initialized
ser cierto no significa que la inicialización se haya completado definitivamente en este caso, por lo que quizás un término ligeramente diferente sería mejor aquí. De nuevo, depende de para qué se esté utilizando.
volatile boolean
sería lo mismo que AtomicBoolean
?
synchronized
bloque, en cuyo caso ya no necesita un AtomicBoolean
, solo un volatile boolean
. ( if(! this.initialized) { synchronized(this) { if(! this.initialized) { initialize(); this.initialized = true; } } }
se asegurará de que solo un subproceso llame initialize
y que todos los demás subprocesos esperen a que lo haga, siempre que initialized
esté marcado volatile
.)
Aquí están las notas (del libro de Brian Goetz ) que hice, que podrían ser de ayuda para usted.
Clases AtomicXXX
Proporcionar implementación de comparación e intercambio sin bloqueo
Aprovecha el soporte proporcionado por el hardware (la instrucción CMPXCHG en Intel) Cuando se ejecutan muchos subprocesos a través de su código que usa estas API de concurrencia atómica, se escalarán mucho mejor que el código que usa monitores / sincronización de nivel de Objeto. Dado que los mecanismos de sincronización de Java hacen que el código espere, cuando hay muchos subprocesos que se ejecutan en sus secciones críticas, se dedica una cantidad considerable de tiempo de CPU a administrar el mecanismo de sincronización en sí (esperar, notificar, etc.). Dado que la nueva API utiliza construcciones de nivel de hardware (variables atómicas) y algoritmos de espera y bloqueo para implementar seguridad de subprocesos, se dedica mucho más tiempo de CPU a "hacer cosas" en lugar de administrar la sincronización.
no solo ofrecen un mejor rendimiento, sino que también brindan una mayor resistencia a los problemas de vida como el punto muerto y la inversión prioritaria.
Hay dos razones principales por las que puede usar un booleano atómico. Primero es mutable, puede pasarlo como referencia y cambiar el valor asociado al booleano, por ejemplo.
public final class MyThreadSafeClass{
private AtomicBoolean myBoolean = new AtomicBoolean(false);
private SomeThreadSafeObject someObject = new SomeThreadSafeObject();
public boolean doSomething(){
someObject.doSomeWork(myBoolean);
return myBoolean.get(); //will return true
}
}
y en la clase someObject
public final class SomeThreadSafeObject{
public void doSomeWork(AtomicBoolean b){
b.set(true);
}
}
Sin embargo, lo más importante es que es seguro para subprocesos y puede indicar a los desarrolladores que mantienen la clase que se espera que esta variable sea modificada y leída desde múltiples subprocesos. Si no utiliza un AtomicBoolean, debe sincronizar la variable booleana que está utilizando declarándola volátil o sincronizando la lectura y escritura del campo.
La AtomicBoolean
clase le da un valor booleano que puede actualizar atómicamente. Úselo cuando tenga múltiples hilos accediendo a una variable booleana.
La descripción general del paquete java.util.concurrent.atomic le ofrece una buena descripción de alto nivel de lo que hacen las clases en este paquete y cuándo usarlas. También recomendaría el libro Java Concurrency in Practice de Brian Goetz.
Extracto de la descripción del paquete
Descripción del paquete java.util.concurrent.atomic: un pequeño conjunto de herramientas de clases que admite la programación segura de subprocesos sin bloqueo en variables individuales. [...]
Las especificaciones de estos métodos permiten que las implementaciones empleen instrucciones atómicas eficientes a nivel de máquina que están disponibles en los procesadores contemporáneos.
Las instancias de las clases AtomicBoolean, AtomicInteger, AtomicLong y AtomicReference proporcionan acceso y actualizaciones a una sola variable del tipo correspondiente. [...]
Los efectos de memoria para accesos y actualizaciones de atómicos generalmente siguen las reglas para volátiles:
- get tiene los efectos de memoria de leer una variable volátil.
- set tiene los efectos de memoria de escribir (asignar) una variable volátil.
- weakCompareAndSet lee atómicamente y escribe condicionalmente una variable, se ordena con respecto a otras operaciones de memoria en esa variable, pero por lo demás actúa como una operación de memoria no volátil ordinaria.
- compareAndSet y todas las demás operaciones de lectura y actualización, como getAndIncrement, tienen los efectos de memoria de leer y escribir variables volátiles.
volatile boolean
vsAtomicBoolean
: stackoverflow.com/questions/3786825/…