[Subprocesamiento múltiple] -Características de la palabra clave volátil

1. ¿Qué es la palabra clave volátil?

En las entrevistas diarias, la volatilidad es sin duda un problema que se menciona con mucha frecuencia. Las principales cuentas públicas también están llenas de análisis de palabras clave volátiles. Entonces, ¿qué es volátil? ? ? ¿Dónde se utilizan? ? ?

En primer lugar, en términos de comprensión de palabras clave, creo que comprender el significado chino de esta palabra clave nos ayuda a recordar. Luego, abra Baidu Translate para buscar volatile y podrá obtener los siguientes resultados:
Inserte la descripción de la imagen aquí
A través de Baidu Translate, puede saber que volatile es un adjetivo, que se usa principalmente para formar Cosas que son fáciles de cambiar, como palabra clave del lenguaje Java, volatile se usa a menudo para modificar un parámetro variable. Entonces tenemos que resolver la siguiente pregunta: ¿qué cambios producirán las variables modificadas volátiles? Es decir, ¿cuál es el papel de la palabra clave volátil?

Dos, la introducción de volátiles

No hay mucho que decir, primero veamos una demostración:

public class VolatileTest {
    
    
	private static boolean flag;
	// 违反可见性验证
	public static void main(String[] args) {
    
    
		flag = true;
		new Thread(() -> {
    
    
			try {
    
    
			//通过线程睡眠达到延时修改flag标记的作用
				Thread.currentThread().sleep(10l);
			} catch (InterruptedException e) {
    
    
				e.printStackTrace();
			}
			flag = false;
		}).start();
		System.out.println("启动循环");
		// 如果上面flag修改生效 程序将退出循环
		while (flag) {
    
    
		}
		System.out.println("退出循环");
	}
}

Resultados experimentales: Los
Inserte la descripción de la imagen aquí
resultados experimentales anteriores se pueden ver que aunque el hilo recién creado ha cambiado el valor de la bandera, el hilo principal no lo percibe, por lo que no puede salir del bucle. El punto aquí es que no debería haber código en el while loop, de lo contrario afectará el resultado. Entonces, ¿qué debemos hacer para que el hilo principal perciba que vale la pena cambiar la bandera? No tiene que adivinar. Este capítulo trata sobre volátiles. Los cambios anteriores se realizan de la siguiente manera al declarar variables:

	private  volatile static boolean flag;

Sí, no te equivocas, solo necesitas agregar una palabra para cambiar el resultado de ejecución del programa:
Inserte la descripción de la imagen aquí
aquí podemos ver que el programa ha salido normalmente, entonces, ¿qué hizo volatile aquí? ?

Tres, las características de los volátiles.

1. Volátil y visibilidad

¿Qué es visibilidad ? La explicación simple de la aditividad es que cuando un subproceso cambia una variable compartida, otros subprocesos pueden aprender el proceso del cambio de variable y el estado más reciente de la variable.
En la demostración anterior, agregamos la palabra clave volátil al indicador de variable compartida.Cuando un hilo intenta cambiar el indicador, la JVM notificará a otros hilos que la memoria caché de variables que leyeron anteriormente ha expirado y debe ir al área de memoria compartida. Tome el último valor de la variable.

Acerca del principio de realización de volátiles La
cuestión de cómo los subprocesos se notifican entre sí para actualizar la caché implica parte del conocimiento de los principios informáticos. Si está interesado, puede aprender sobre la barrera de la memoria y el protocolo de coherencia de la caché de la CPU. Gané entrar en detalles aquí.

2. Volátil y atomicidad

Hemos demostrado que volatile tiene visibilidad a través de la demostración anterior, entonces, ¿el soporte volátil atómico entre las tres características de la programación concurrente? No hay mucho que decir, ve a DEMO:

public class VolatileAtomicity {
    
    
	public volatile int count = 0;

	private void addCount() {
    
    
	//count 自增
		for (int i = 0; i < 100; i++) {
    
    
			count++;
		}
		System.out.println("count = " + count);
	}

	public static void main(String[] args) {
    
    
		VolatileAtomicity volatileAtomicity = new VolatileAtomicity();
		// 循环创建1000个新线程 每个线程count自增100次 期望结果为100000
		for (int i = 0; i < 1000; i++) {
    
    
			new Thread(() -> {
    
    
				volatileAtomicity.addCount();
			}).start();
			;
		}
	}
}

Resultado esperado: 100000
Resultado de la operación:

Inserte la descripción de la imagen aquí
Aquí vemos que aunque agregamos la modificación de la palabra clave volátil al recuento de variables compartidas, el resultado final de ejecución no cumplió con nuestras expectativas. De hecho, la razón principal es que count ++ lo desensambló cuando se analizó el jvm:

  1. Primero lea el valor del recuento. En este momento, debido a que volatile tiene visibilidad, el valor del recuento es el último valor en este momento.
  2. En este momento, se calcula el valor de count. Cabe señalar que otros subprocesos pueden haber modificado el valor de count en este momento, por lo que el valor de count + 1 en este momento ha violado la política de seguridad de subprocesos.
  3. Vuelva a asignar el resultado de count + 1 para contar. En este momento, el valor de count se ha desviado de la expectativa
    . Como se puede ver en el ejemplo anterior, volatile solo puede garantizar la visibilidad cuando la lectura vale la pena, pero no puede garantizar simultaneidad durante las operaciones posteriores Problemas de seguridad de subprocesos causados ​​por subprocesos, por lo que volátil no es atómico .

Aquí necesitamos hacer una explicación complementaria sobre la visibilidad de volátiles : La visibilidad de volátiles se refleja en el hecho de que cuando el hilo lee la variable, se obtiene la última variable, y la última variable no se obtendrá cuando se realice la operación. después de la lectura Esta parte del diseño conceptual de la memoria leer y escribir barreras, los estudiantes interesados ​​pueden Baidu por sí mismos.

3. Volátil y orden

Antes de entender el orden, primero debemos entender un concepto que es el reordenamiento de las instrucciones de la CPU.

Cuando la CPU ejecuta el código, no lo ejecuta estrictamente en el orden en el que está escrito. En su lugar, ejecuta las instrucciones después de un reordenamiento apropiado bajo el principio de como-si-serie. Esto es principalmente para mejorar el eficiencia de ejecución de la CPU y reducir el tiempo de inactividad.

Entonces, lo primero que tenemos que hacer es demostrar que la CPU tiene reordenamiento de instrucciones. No hablemos de la demostración:

public class VolatileOrderliness {
    
    

	private static long a = 0;
	private static long b = 0;
	private static long c = 0;
	private static long d = 0;
	private static long e = 0;
	private static long f = 0;
	private static long g = 0;
	private static long h = 0;

	public static long count = 0;

	public static void main(String[] args) {
    
    
		// 由于cpu指令重排发生存在概率 所以使用死循环调用 然后再出现的时候通过break跳出循环
		for (;;) {
    
    
			a = 0;
			b = 0;
			c = 0;
			d = 0;
			e = 0;
			f = 0;
			g = 0;
			h = 0;
			count++;
			Thread t1 = new Thread(() -> {
    
    
				a = 1;
				c = 101;
				d = 102;
				g = b;
			});
			Thread t2 = new Thread(() -> {
    
    
				b = 1;
				e = 201;
				f = 202;
				h = a;
			});
			t1.start();
			t2.start();
			try {
    
    
				t1.join();
				t2.join();
				String result = "count = " + count + " g = " + g + ", h=" + h;
				if (g == 0 && h == 0) {
    
    
					// 当g 和h 都出现0的时候 一定是发生了指令重排序
					System.err.println(result);
					break;
				} else {
    
    
					System.out.println(result);
				}
			} catch (InterruptedException e1) {
    
    
				e1.printStackTrace();
			}

		}

	}

}


Resultados de la operación:
Inserte la descripción de la imagen aquí
Primero, analizamos la demostración. Ya sea que el subproceso t1 se ejecute primero o el subproceso t2 se ejecute primero, a su primera línea de código se le asigna un valor de 1 a ayb, lo que significa que bajo la lógica de código normal, como La asignación gyh ejecutada por última vez por un hilo debe tener un valor de 1, pero en este momento los valores de gyh son ambos 0, lo que indica que la CPU interrumpió el orden de ejecución del código y lo reordenó al ejecutar el código. Como sigue: La
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
CPU cambia la operación de asignación de gyh a la operación de asignación de ay b. En realidad, es muy simple resolver este problema. Solo necesitamos agregar la palabra clave volátil a ay b.

Cuatro, volátil entrevista relacionada

Aquí también resumí algunas preguntas comunes de entrevistas volátiles para compartir con ustedes.

1. Hable sobre qué escenarios se aplican generalmente a volátiles.
Respuesta: El escenario de aplicación más simple de volátiles es usarlo en objetos singleton implementados en el modo de bloqueo de verificación doble. En el modo DCL singleton, volátil se usa principalmente para evitar que los subprocesos obtengan Variables semiinicializadas causadas por el reordenamiento de instrucciones.
2. ¿Cuáles son las similitudes y diferencias entre volátil y sincronizado?
Respuesta:
1) Volátil se usa principalmente para modificar variables, mientras que sincronizado se usa principalmente para modificar bloques de código.
2) Volátil no puede garantizar atomicidad, sincronizado puede
3) Volátil no causará bloqueo de hilo, sincronizado causará

De acuerdo, si tiene alguna pregunta o cree que el autor está equivocado, ¡deje un mensaje!
¡buena suerte!

Supongo que te gusta

Origin blog.csdn.net/xiaoai1994/article/details/110437416
Recomendado
Clasificación