Tabla de contenido
Que es CAS
CAS significa comparar e intercambiar, comparar e intercambiar.
CAS es una operación atómica y CAS utiliza un mecanismo de bloqueo optimista.
Muchas funciones en JUC se basan en CAS. Varias clases atómicas usan CAS para implementar operaciones atómicas en la capa inferior. Se utiliza para resolver el problema de seguridad de la concurrencia.
Además, he recopilado más de 20 años de puntos de conocimiento de entrevistas de empresa, así como varios puntos de conocimiento básicos de Java para compartir con usted de forma gratuita. Si desea información, haga clic (haga clic aquí) para obtenerla gratis .
Problemas de seguridad de simultaneidad
Da un ejemplo típicoi++
public class AddTest {
public volatile int i;
public void add() {
i++;
}
}
Por javap -c AddTest
ver las instrucciones de código de bytes, agregue el método:
public void add();
Code:
0: aload_0
1: dup
2: getfield #2 // Field i:I
5: iconst_1
6: iadd
7: putfield #2 // Field i:I
10: return
i++
Se divide en varias instrucciones:
- Ejecutar
getfield
para obtener el valor de memoria original; - Ejecutar
iadd
para agregar 1 operación; - Ejecute la
putfield
escritura para volver a escribir el valor acumulado en la memoria.
Suponga una situación:
- Cuando
线程 1
llega la ejecucióniadd
, dado que aún no se ha ejecutadoputfield
, el valor en el área de la memoria principal no se actualizará en este momento. - En este momento,
线程 2
entra y comienza a ejecutarse, simplemente copie el valor del área de memoria principal en el área de memoria privada. 线程 1
Simplemente ejecuteputfield
y actualice el valor del área de memoria principal, luego线程 2
la copia en este momento es la anterior. Apareció el error.
¿Cómo resolver?
El más simple es agregar sincronizado al método de agregar.
public class AddTest {
public volatile int i;
public synchronized void add() {
i++;
}
}
Aunque simple y resuelto el problema, el rendimiento no es bueno.
La mejor solución debería ser usar el programa CAS que viene con JDK , como en el ejemplo anterior, use la AtomicInteger
clase
public class AddIntTest {
public AtomicInteger i;
public void add() {
i.getAndIncrement();
}
}
Principio subyacente
El principio de CAS no es complicado:
- Tres parámetros, un valor de memoria actual V, valor esperado A, valor actualizado B
- Si y solo si el valor esperado A y el valor de memoria V son iguales, modifique el valor de memoria a B y devuelva verdadero
- De lo contrario, no haga nada y devuelva falso
Haga un AtomicInteger
análisis de clase, primero mire el código fuente:
Mi entorno aquí es Java11, si es Java8, algunos nombres internos son ligeramente diferentes.
public class AtomicInteger extends Number implements java.io.Serializable {
private static final long serialVersionUID = 6214790243416807050L;
/*
* This class intended to be implemented using VarHandles, but there
* are unresolved cyclic startup dependencies.
*/
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long VALUE = U.objectFieldOffset(AtomicInteger.class, "value");
private volatile int value;
//...
}
Unsafe
Clase, esta clase rara vez es útil para el desarrollo general.
Unsafe
La capa inferior de la clase está implementada en C / C ++, por lo que todos sus métodos son modificados por la palabra clave nativa.
Puede proporcionar operaciones atómicas a nivel de hardware, como obtener la ubicación de un atributo en la memoria y modificar el valor de campo de un objeto.
punto clave:
-
AtomicInteger
El valor almacenado por la clase está en elvalue
campo y elvalue
campo esvolatile
-
En el bloque de código estático, y obtenga la
Unsafe
instancia, obtenga elvalue
desplazamiento del campo en la memoriaVALUE
A continuación, de vuelta al ejemplo anterior:
Como se indicó anteriormente, la getAndIncrement()
capa inferior del método utiliza tecnología CAS para garantizar la seguridad de la concurrencia.
public final int getAndIncrement() {
return U.getAndAddInt(this, VALUE, 1);
}
getAndAddInt()
método:
public final int getAndAddInt(Object o, long offset, int delta) {
int v;
do {
v = getIntVolatile(o, offset);
} while (!weakCompareAndSetInt(o, offset, v, v + delta));
return v;
}
v
getIntVolatile(o, offset)
Obtener por método, su propósito es obtener el valor o
en el offset
desplazamiento, que o
es AtomicInteger
el valor almacenado en la clase, es decir value
, el valor del offset
desplazamiento de memoria, es decir VALUE
.
Enfoque , weakCompareAndSetInt
es realizar el método central CAS
- Si la
o
suma esv
igual, prueba que ningún otro hilo ha cambiado esta variable, y luego elv
valor se actualiza av + delta
, dondedelta
es el valor incremental actualizado. - Por el contrario, CAS continúa funcionando en modo de giro, y este paso también es una operación atómica.
análisis:
AtomicInteger
El valor original se establece en A,线程 1
y线程 2
cada uno tiene una copia, el valor es A.
线程 1
AlgetIntVolatile(o, offset)
obtener el valor A, se线程 1
suspende en este momento .线程 2
ElgetIntVolatile(o, offset)
valor A también se obtiene a través del método, y elweakCompareAndSetInt
método se ejecuta para comparar el valor de la memoria como A, y el valor de la memoria se modifica con éxito a B.- En este momento , comparo el método de
线程 1
ejecuciónweakCompareAndSetInt
y encuentro que el valor A en mi mano es inconsistente con el valor B de la memoria, lo que indica que el valor ha sido modificado de antemano por otros hilos. 线程 1
Vuelva a ejecutargetIntVolatile(o, offset)
para obtener el valor del valor nuevamente, debido a que el valor de la variable es modificado por volátil y tiene visibilidad, el hilo A continúa ejecutando laweakCompareAndSetInt
comparación y el reemplazo hasta que tiene éxito
CAS necesita atención
Restricciones de uso
CAS es una operación atómica soportada por la CPU. Su atomicidad está garantizada a nivel de hardware. No puede ser usado directamente por usuarios normales en Java, y solo puede ser usado con la ayuda atomic
de clases atómicas bajo el paquete, con flexibilidad limitada.
Sin embargo, CAS solo puede garantizar la atomicidad de la operación de una sola variable. Cuando hay múltiples variables involucradas, CAS no puede hacer nada.
La atomicidad no garantiza necesariamente la seguridad de los subprocesos. Por ejemplo, en Java, se necesita volatile
cooperación para garantizar la seguridad de los subprocesos.
Problema de ABA
concepto
CAS tiene un problema, un ejemplo es el siguiente:
线程 1
Quite A de la ubicación de memoria V- En este momento, A
线程 2
también se toma de la ubicación de memoria V - En este momento
线程 1
en el estado suspendido,线程 2
cambie el valor de la posición V a B, y finalmente a A 线程 1
Vuelva a ejecutar en este momento y encuentre que el valor de la posición V no ha cambiado y continúe ejecutando como se esperaba.
Aunque 线程 1
todavía tuvo éxito en este momento , no cumplió con nuestras expectativas reales, y fue equivalente a jugar al 线程 2
gato de algalia para el 线程 1
príncipe.
Este es el llamado problema ABA
solución
Introducir referencias atómicas, operaciones atómicas con números de versión.
Lleve un número de versión a cada una de nuestras operaciones, para que podamos evitar problemas de ABA. Tanto la idea de bloqueo optimista.
-
Cada vez que cambia el valor en la memoria, se actualiza el número de versión.
-
Al realizar operaciones CAS, al comparar los valores en la memoria, también se comparan los números de versión, sólo cuando los dos no han cambiado puede la ejecución tener éxito.
-
AtomicStampedReference
Las clases en Java usan números de versión para resolver problemas ABA.
Problemas de costos bajo alta competencia
-
En un entorno altamente competitivo con una alta probabilidad de conflictos simultáneos, si el CAS falla todo el tiempo, siempre volverá a intentarlo y la sobrecarga de la CPU es relativamente alta.
-
Una forma de pensar sobre este problema es introducir un mecanismo de salida, como no salir después de que el número de reintentos supere un cierto umbral.
-
Más importante aún, evite utilizar el bloqueo optimista en un entorno altamente competitivo.
Además, he recopilado más de 20 años de puntos de conocimiento de entrevistas de empresa, así como varios puntos de conocimiento básicos de Java para compartir con usted de forma gratuita. Si desea información, haga clic (haga clic aquí) para obtenerla gratis .