Directorio de artículos
Prefacio
Primero, entendemos brevemente el modelo de memoria de Java, y luego damos lugar a problemas de visibilidad de la memoria basados en un fragmento de código.
-
Modelo de memoria de Java El modelo de memoria de
Java estipula que todas las variables se almacenan en la memoria principal. Cada subproceso tiene su propia memoria de trabajo. La memoria de trabajo del subproceso almacena las variables utilizadas por el subproceso (estas variables son de la memoria principal Copiado de) . Todas las operaciones (lectura, asignación) de variables por subprocesos deben realizarse en la memoria de trabajo.Los diferentes subprocesos no pueden acceder directamente a las variables en la memoria de trabajo del otro, y la transferencia de valores de variables entre subprocesos debe completarse a través de la memoria principal . -
Ejemplo de código
public class 内存可见性问题 {
public static void main(String[] args) {
MyRunable0 myRunable0 = new MyRunable0();
Thread th = new Thread(myRunable0);
th.start();
while (true){
//程序没有进入,线程在其工作内存中将共享变量值修改为true,但是没能及时刷新到主存中
if(myRunable0.isFlag()){
System.out.println("进来了");
break;
}
}
}
}
class MyRunable0 implements Runnable{
boolean flag=false;
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
flag=true;
System.out.println("线程将flag改成"+flag);
}
}
- resultado de la operación
- Visibilidad
La modificación de un valor de variable compartida por un hilo puede ser visto por otros hilos en el tiempo. - Atomicidad
Atomicidad significa que la operación es indivisible. Ya sea de múltiples núcleos o de un solo núcleo, una cantidad atómica, solo un hilo puede operar en él a la vez. - Logra condiciones visibles
- El valor de la variable compartida modificado por el hilo se puede actualizar de la memoria de trabajo a la memoria principal a tiempo
- Otros subprocesos pueden actualizar el último valor de las variables compartidas de la memoria principal a su propia memoria de trabajo a tiempo
- Implementación de visibilidad admitida en el nivel de lenguaje Java
- sincronizado
- volátil
Uno, sincronizado para lograr visibilidad
1.se puede lograr sincronizado
- Atomicidad (sincronización)
- Visibilidad
2. Dos regulaciones de JVM sobre sincronizadas
- Antes de que se desbloquee el subproceso, el último valor de la variable compartida debe vaciarse en la memoria principal.
- Cuando el hilo está bloqueado, el valor de la variable compartida en la memoria de trabajo se borrará, por lo que al usar la variable compartida, el último valor debe volver a leerse desde la memoria principal.
3. Código
while (true){
//使用 synchronized实现可见性,注意锁的使用
synchronized (myRunable0){
if (myRunable0.isFlag()) {
System.out.println("进来了");
break;
}
}
}
4. Desventajas de sincronizado
- No se puede controlar la longitud real del bloque
- El bloqueo no se puede interrumpir
- Baja eficiencia
Dos, volátil logra visibilidad
1. Se puede lograr lo volátil
- Problemas de visibilidad
- Sin garantía de atomicidad
2. Principio de implementación
Se logra agregando barreras de memoria y prohibiendo el reordenamiento de la optimización.
- Al realizar una operación de escritura en una variable volátil, se agregará una instrucción de barrera de tienda después de la operación de escritura.
- Al realizar una operación de lectura en una variable volátil, se agrega una instrucción de barrera de carga antes de la operación de lectura
En términos sencillos, cada vez que un hilo accede a una variable volátil, el valor de la variable se ve obligado a volver a leer desde la memoria principal. Cuando la variable cambia, obligará al hilo a actualizar el último valor al principal. memoria. De esta manera, en cualquier momento, diferentes hilos siempre pueden ver el último valor de la variable.
3. Código
//在共享变量前添加volatile关键字
volatile boolean flag=false;
4. Escenarios aplicables de volátiles
- La operación de escritura de la variable no depende de su valor actual
- La variable no se incluye en una invariante con otras variables.
3. Algoritmo CAS (Compare-And-Swep)
1. Información general
- CAS, Compare and Swap compare e intercambie.Hay un total de tres operandos, un valor de memoria v, un valor antiguo de memoria local de subproceso a (el valor antes de la operación deseada) y un valor nuevo b. Durante la operación, compare el valor antiguo a y el valor de memoria v para ver los cambios Si no hay cambio, el valor de memoria v se puede actualizar al nuevo valor b. Si hay un cambio, no se cambiará.
2. Código
public class CAS算法 {
public static void main(String[] args) {
Mrunable mrunable = new Mrunable();
for (int i = 0; i < 10; i++) {
new Thread(mrunable).start();
}
}
}
class Mrunable implements Runnable{
//Java提供好的原子变量
AtomicInteger i=new AtomicInteger(1);
public AtomicInteger getI() {
return i;
}
@Override
public void run() {
while (true){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
//使用原子变量调用相应的方法完成需求
System.out.println(i.getAndIncrement());
}
}
}
para resumir
Comparación sincronizada y volátil
- Volátil no requiere bloqueos, es más liviano que sincronizado y no bloquea los hilos
- Desde la perspectiva de la visibilidad de la memoria, las operaciones de lectura volátiles equivalen al bloqueo y las operaciones de escritura volátiles equivalen al desbloqueo.
- Sincronizado puede garantizar tanto la visibilidad como la atomicidad, mientras que lo volátil solo puede garantizar la visibilidad y no puede garantizar la atomicidad.