Muchos amigos pueden haber oído hablar de la palabra clave volátil y pueden haberla usado. Antes de Java 5, era una palabra clave controvertida, ya que usarla en programas a menudo resultaba en resultados inesperados. Solo después de Java 5, la palabra clave volátil recuperó su vitalidad. Aunque la palabra clave volátil es literalmente simple de entender, no es fácil usarla bien.
1. Prefacio
JMM proporciona una definición de variable volátil, bloques finales y sincronizados para garantizar la visibilidad.
Para las variables modificadas con volátiles, el hilo leerá el valor más modificado de la variable cada vez que usa la variable. Volátil se usa fácilmente y se usa para operaciones atómicas. He escrito algunos ejemplos de prueba, puedes probarlo.
2. Programa principal
clase pública Main {public static void main (string [] args) lanza interruptedException {list <Shifre> ThreadList = new ArrayList <Shifre> (); for (int i = 0; i <10; ++ i) {Thread Thread = new Thread (new RunNable () {@OverridPublic Void Run () {Sencillo.holder.instance.add ();}}); ThreadList.Add (Thread); Thread.Start ();} para (Thread Thread: ThreadList) Thread.Join (); System.out.println (single.holder.instance.x);}}}3. Prueba de modo singleton
1. Sin volátil, sin sincronizado
clase única {public int x = 0; public void add () {try {timeUnit.milliseConds.sleep (50);} capt (interruptedException e) {e.printstacktrace ();} ++ this.x;} Holder de clase estática pública {public sencillo sencillo = nueva instancia = nueva ();}}Resultados de salida: 8, 9 y 10 han aparecido. Puede ejecutar más e intentar más y encontrará resultados diferentes.
2. Hay volátil, pero no se ha sincronizado
clase única {public volatile int x = 0; public void add () {try {timeUnit.milliseConds.sleep (50);} capt (interruptedException e) {E.PrintStackTRace ();} ++ this.x;} Holder de clase estática pública {Public Static Sing Singster = new ();}}}Resultado de salida: el número máximo de ocurrencias es 9 y 10.
3. Sin volátil, sincronizado
clase única {public int x = 0; public sincronizado void add () {try {timeUnit.milliseConds.sleep (50);} catch (interruptedException e) {E.PrintStackTRace ();} ++ this.x;} Holder de clase estática pública {Public sencillo instancia = nueva sola ();}}}Resultado de salida: no importa cuántas veces se ejecute, serán 10.
4. Acerca de la aplicación de Volátil en DCL (bloqueo de doble verificación)
clase pública Lazysingleton {private int somefield; private static Lazysingleton instancia; private lazysingleton () {this.somefield = new Random (). Nextint (200) +1; // (1)} public static Lazysingleton getInstance () {if (instance == null) {// (2) sincronizado (lazysingleton.class) {// (3) if (instance == null) {// (4) instancia = nueva lazysingleton (); // (5)}}} instancia de retorno; // (6)} public int getSomeField () {return this.Somefield; // (7)}}En primer lugar, ¡permítanme explicar por qué este método de escritura no funciona en Java!
Suponga que el hilo I está llamando al método getInstance () por primera vez, y luego el hilo II también llama al método getInstance () y getMomeField (). Lo que queremos explicar es que la declaración del hilo I (1) no se produce antes de la declaración del hilo II (7). Cuando Thread II ejecuta la declaración (2) del método getInstance (), dado que el acceso a la instancia no está en el bloque sincrónico, el hilo II puede o no observar la escritura de Thread I a la instancia en la declaración (5), es decir, el valor de la instancia puede estar vacío o no vacío. Primero asumimos que el valor de instancia no está vacío, por lo que observamos ese hilo que escribe la instancia. En este momento, Thread II ejecutará la declaración (6) y devolverá directamente el valor de esta instancia, y luego llamará al método getSomeField () en esta instancia. Este método también se llama sin ninguna sincronización. Por lo tanto, toda la operación del subproceso II se llama sin sincronización. Esto muestra que no hay una relación antes de la declaración (1) del hilo I y la declaración (7) del hilo II. Esto significa que el hilo II puede no ser capaz de observar el valor escrito por el hilo I a algún archivo en la declaración (1). Este es el problema con DCL. Es ridículo, ¿verdad? DCL originalmente tenía la intención de escapar de la sincronización, y logró este objetivo. Es precisamente por esto que finalmente fue castigado. Hay serios errores en tales programas, aunque la probabilidad de que se descubra dicho error es definitivamente mucho menor que la probabilidad de ganar la lotería, y es fugaz. Lo que es más aterrador es que incluso si sucede, no pensarás que fue causado por DCL.
Entiendo que tanto Thread I como Hild II tienen su propio almacenamiento de trabajo. Después de un hilo, crea la instancia, el tiempo para refrescar a la memoria es incierto, por lo que es completamente posible que el hilo II no pueda observar el valor escrito por el hilo I a alguna fila en la declaración (1).
Entonces, debido a que hay una regla adicional de HABIERSA ADECUADA EN JAVA 5:
• Escriba la operación en el campo volátil que ocurre antes de las operaciones de lectura posteriores en el mismo campo.
Usando esta regla, podemos declarar la instancia como volátil, es decir: instancia de lazysingleton estática volátil privada;
De acuerdo con esta regla, podemos obtener la declaración del hilo I (5) -> oración del hilo II (2) (es decir, el hilo), de acuerdo con la regla de un solo hilo, la declaración del hilo I (1) -> oración del hilo I (5) y la oración del hilo II (2) -> oración del hilo II (7), y de acuerdo con las reglas de entrega, hay la declaración de hilo I (1) -> de hilo de hilo II (7). Escriba el valor del hilo I a algún archivo de la declaración (1), y el programa puede obtener el comportamiento correcto.
Suplemento: Antes de Java5, no hay diferencia entre la semántica sincrónica del campo final y otras variables. En Java5, una vez que la variable final se establece en el constructor (siempre que esta referencia no se filtre en el constructor), otros hilos definitivamente verán los valores establecidos en el constructor. El problema con DCL es solo que vemos el valor predeterminado de la variable miembro del objeto, por lo que podemos establecer la variable Somefield de Lazysingleton en final, para que pueda ejecutarse correctamente en Java5.
El contenido anterior es el conocimiento de las palabras clave volátiles en Java presentadas por el editor. ¡Espero que sea útil para todos!