¿Id = 1-id es atómico?
De la página 291 de OCP Java SE 6 Programmer Practice Exams, pregunta 25:
public class Stone implements Runnable {
static int id = 1;
public void run() {
id = 1 - id;
if (id == 0)
pick();
else
release();
}
private static synchronized void pick() {
System.out.print("P ");
System.out.print("Q ");
}
private synchronized void release() {
System.out.print("R ");
System.out.print("S ");
}
public static void main(String[] args) {
Stone st = new Stone();
new Thread(st).start();
new Thread(st).start();
}
}
Una de las respuestas es:
La salida podría ser
P Q P Q
He marcado esta respuesta como correcta. Mi razonamiento:
- Estamos comenzando dos hilos.
- Primero entra
run()
. - De acuerdo con JLS 15.26.1, primero evalúa
1 - id
. El resultado es0
. Se almacena en la pila del hilo. Estamos a punto de salvar que0
para estáticoid
, pero... - Boom, scheduler elige el segundo hilo a ejecutar.
- Entonces, el segundo hilo entra en
run()
. Staticid
sigue siendo1
, por lo que ejecuta el métodopick()
.P Q
está impreso. - Scheduler elige el primer hilo a ejecutar. Toma
0
de su pila y guarda a estáticoid
. Así, el primer hilo también ejecutapick()
e imprimeP Q
.
Sin embargo, en el libro está escrito que esta respuesta es incorrecta:{[21]]}
Es incorrecta porque la línea
id = 1 - id
intercambia el valor deid
entre0
y1
. No hay posibilidad de que el mismo método se ejecute dos veces.
No estoy de acuerdo. Creo que hay alguna posibilidad para el escenario que presenté anteriormente. Tal intercambio no es atómico. ¿Me equivoco?
2 answers
¿Me equivoco?
No, tienes toda la razón, al igual que tu línea de tiempo de ejemplo.
Además de no ser atómico, no se garantiza que la escritura a id
será recogida por el otro hilo de todos modos, dado que no hay sincronización y el campo no es volátil.
Es algo desconcertante que material de referencia como este sea incorrecto : (
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-23 13:01:29
En mi opinión, la respuesta en los Exámenes de Práctica es correcta. En este código, está ejecutando dos subprocesos que tienen acceso al mismo id de variable estática. Las variables estáticas se almacenan en el montón en Java, no en la pila. El orden de ejecución de los runnables es impredecible.
Sin embargo, para cambiar el valor de id cada hilo:
- hace una copia local del valor almacenado en la dirección de memoria de id al registro de CPU;
- realiza la operación
1 - id
. Estrictamente hablando, aquí se realizan dos operaciones(-id and +1)
; - mueve el resultado de nuevo al espacio de memoria de
id
en el montón.
Esto significa que aunque el valor id se puede cambiar simultáneamente por cualquiera de los dos hilos, solo los valores inicial y final son mutables. Los valores intermedios no serán modificados entre sí.
Además, el análisis del código puede mostrar que en cualquier momento, id solo puede ser 0 o 1.
Prueba:
Valor inicial id = 1; Un hilo lo cambiará a 0 (
id = 1 - id
). Y el otro hilo lo devolverá a 1.Valor inicial id = 0; Un hilo lo cambiará a 1 (
id = 1 - id
). Y el otro hilo lo devolverá a 0.
Por lo tanto, el estado de valor de id es discreto, ya sea 0 o 1.
Fin de la prueba.
Puede haber dos posibilidades para esto código:
Posibilidad 1. El hilo uno accede primero a la variable id. Entonces el valor de id (
id = 1 - id
cambia a 0. A partir de entonces, solo se ejecutará el métodopick ()
, imprimiendoP Q
. El hilo dos, evaluará id en ese momentoid = 0
; el métodorelease()
se ejecutará imprimiendo R S. Como resultado, se imprimiráP Q R S
.Posibilidad 2. El hilo dos accede primero a la variable id. Entonces el valor de id (
id = 1 - id
cambia a 0. A partir de entonces, sólo el métodopick ()
ser ejecutado, imprimiendoP Q
. El hilo uno, evaluará id en ese momentoid = 0
; el métodorelease()
se ejecutará imprimiendo R S. Como resultado, se imprimiráP Q R S
.
No hay otras posibilidades. Sin embargo, cabe señalar que las variantes de P Q R S
como P R Q S
o R P Q S
, etc. puede imprimirse debido a que pick()
es un método estático y, por lo tanto, se comparte entre los dos hilos. Esto conduce a la ejecución simultánea de este método que podría resultar en la impresión de la letras en un orden diferente dependiendo de su plataforma.
Sin embargo, en cualquier caso, nunca se ejecutará el método pick()
o release ()
dos veces como son mutuamente excluyentes. Por lo tanto, P Q P Q
no será una salida.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-27 21:43:47