que - swingworker java ejemplo
¿Por qué Java no ve el valor actualizado de otro hilo? (5)
Mire este código (tomado del libro Effective Java)
import java.util.concurrent.TimeUnit;
public class Main {
private static boolean stopReq;
public static void main(String[] args) throws InterruptedException {
Thread bgw = new Thread(new Runnable()
{
public void run(){
int i = 0;
while(!stopReq){ i++;}
}
});
bgw.start();
TimeUnit.SECONDS.sleep(1);
stopReq = true;
}
}
¿Por qué el subproceso bgw
se atasca en un ciclo infinito? ¿Está almacenando en caché su propia copia de stopReq
cuando alcanzó el bucle? Entonces, ¿nunca ve el valor actualizado del otro hilo?
Entiendo que la solución a este problema sería la sincronización o una variable volátil, pero tengo curiosidad por saber por qué esta implementación actual no funciona.
Gracias
Debería leer más sobre el Modelo de memoria Java para comprender mejor todas las implicaciones.
En breve, la variable stopReq no es volátil o está incluida en un bloque sincronizado que le da libertad a la máquina virtual para usar un almacenamiento local optimizado (por ejemplo, registros, etc.) que no garantiza la propagación inmediata de los cambios a través de los hilos.
Cuando declara la variable como volátil, la VM se asegurará de que después de cada variable se inserte una "barrera de escritura de memoria" que forzará todos los cambios locales a derramarse a la ubicación real de la memoria, haciéndolo visible para todos los demás hilos ( la misma barrera se coloca al final de un bloque sincronizado, por ejemplo)
Haga que stopReq sea verdadero, luego se detendrá. Nuevamente está configurando el stopReq en falso, debido a que while la condición de ciclo es verdadera siempre y está en un bucle infinito.
Para ser muy específico acerca de su consulta, para aprovechar al máximo el rendimiento del hardware multiprocesador moderno, en ausencia de sincronización, las JVM permitieron que el compilador reordene las operaciones y los valores de caché en los registros y cachés específicos del procesador. Como el hilo principal escribe en stopReq sin sincronización, debido a la reordenación y el almacenamiento en caché del hilo BTW puede que nunca se vea el valor escrito y se repita para siempre.
Cuando utiliza la sincronización o la volatilidad, garantizan VISIBILIDAD y obligan al compilador a no almacenar en caché y eliminar los cambios en la memoria principal.
Probé esto, y no, las variables son las mismas. El ejemplo también compila para mí.
El error está aquí:
Su ciclo while continúa, siempre que! StopReq sea verdadero, eso significa que stopReq es falso. Y después de 1 segundo, configura stopReq en false, esto no cambia nada. Si lo configura en verdadero,! StopReq se convertirá en falso y su ciclo finalizará.
Tu explicación es correcta .
El compilador detecta que stopReq
nunca se modifica en el ciclo y, dado que no es volatile
, optimiza la instrucción while(!stopReq)
en while(true)
.
Aunque el valor cambia más tarde, el hilo ni siquiera lo lee.