mvc - spring java tutorial
¿Por qué no es una buena práctica sincronizar en Boolean? (4)
No puedo entender la razón por la que deberíamos "nunca sincronizar en Boolean"
Necesita synchronize
en una instancia de objeto constante . Si sincronizó en cualquier objeto que está asignando (es decir, cambiando el objeto), entonces el objeto no es constante y diferentes hilos se sincronizarán en diferentes instancias de objetos. Debido a que se sincronizan en diferentes instancias de objetos, múltiples hilos entrarán en el bloque protegido al mismo tiempo y las condiciones de carrera ocurrirán. Esta es la misma respuesta para sincronizar en Long
, Integer
, etc.
Boolean isOn;
...
synchronized (isOn) {
if (isOn) {
// this changes the synchronized object isOn to another object
// so another thread can then enter the synchronized with this thread
isOn = false;
Para empeorar las cosas (como @McDowell señaló en su respuesta), cualquier Boolean
creado mediante autoboxing ( isOn = true
) es el mismo objeto que Boolean.TRUE
(o .FALSE
) que es un singleton en el ClassLoader
en todos los objetos . El objeto de bloqueo debe ser local para la clase en la que se utiliza, de lo contrario se bloqueará el mismo objeto singleton que otras clases podrían estar bloqueando en otros casos de bloqueo si están cometiendo el mismo error.
El patrón adecuado si necesita bloquear un booleano es definir un objeto de bloqueo private final
:
private final Object lock = new Object();
...
synchronized (lock) {
...
O también debería considerar usar el objeto AtomicBoolean
que significa que puede que no tenga que synchronize
en absoluto.
private final AtomicBoolean isOn = new AtomicBoolean(false);
...
// if it is set to false then set it to true, no synchronization needed
if (isOn.compareAndSet(false, true)) {
statusMessage = "I''m now on";
} else {
// it was already on
statusMessage = "I''m already on";
}
En su caso, dado que parece que necesita activar / desactivar el encendido con subprocesos, aún necesitará synchronize
en el objeto de lock
y configurar el booleano y evitar la condición de prueba / establecimiento de carrera:
synchronized (lock) {
if (isOn) {
isOn = false;
statusMessage = "I''m off";
// Do everything else to turn the thing off
} else {
isOn = true;
statusMessage = "I''m on";
// Do everything else to turn the thing on
}
}
Por último, si espera statusMessage
al statusMessage
desde otros hilos, entonces debe marcarse como volatile
menos que también se synchronize
durante el get.
Mi arquitecto siempre dice que
Nunca sincronizar en Boolean
No puedo entender el motivo y realmente agradecería que alguien pudiera explicar con un ejemplo por qué no es una buena práctica. Código de muestra de referencia
private Boolean isOn = false;
private String statusMessage = "I''m off";
public void doSomeStuffAndToggleTheThing(){
// Do some stuff
synchronized(isOn){
if(isOn){
isOn = false;
statusMessage = "I''m off";
// Do everything else to turn the thing off
} else {
isOn = true;
statusMessage = "I''m on";
// Do everything else to turn the thing on
}
}
}
Creo que tu problema está más sincronizado que sincronizando en booleanos. Imagine que cada hilo es un camino, donde los enunciados (vagones) van uno tras otro. En algún punto puede haber una intersección: sin un semáforo pueden ocurrir colisiones. El lenguaje Java tiene una forma integrada de describir esto: dado que cualquier objeto puede ser una intersección, cualquier objeto tiene un monitor asociado que actúa como un semáforo. Cuando usa sincronizado en su código, está creando un semáforo, por lo tanto, debe usar el mismo para todos los caminos (hilos). Entonces, este problema no es realmente específico de booleano porque solo existen dos booleanos, este problema ocurre cada vez que se sincroniza en una variable de instancia y luego apunta la misma variable a un objeto diferente. Por lo tanto, su código es incorrecto con booleanos, pero es igualmente peligroso con enteros, cadenas y cualquier objeto si no comprende lo que está sucediendo.
Editar: la respuesta de Gray es correcta.
Lo que quiero agregar es: su arquitecto tiene razón, si desde la perspectiva de Boolean
es inmutable , ¿por qué sincronizarlo? Pero el hilo múltiple es complejo y se basa en el escenario.
private Boolean isOn = false;
public void doSomeStuffAndToggleTheThing(){
synchronized(isOn){
Esta es una idea terrible isOn
hará referencia al mismo objeto que Boolean.FALSE
que está disponible públicamente. Si cualquier otra parte del código mal escrito también decide bloquear este objeto, dos transacciones completamente independientes tendrán que esperar el uno al otro.
Los bloqueos se realizan en instancias de objetos , no en las variables que los referencian: