JUC Learning (4) "Clase de operación atómica atómica"

Prefacio

El concepto de atomicidad es un tema común en la programación multiproceso. La llamada atomicidad significa que una o más operaciones deben ejecutarse o no ejecutarse en absoluto. No puede haber un éxito parcial y un fracaso parcial.
En subprocesos múltiples, si varios subprocesos actualizan una variable compartida al mismo tiempo, es posible que obtenga un valor inesperado. Por ejemplo, i = 1. El hilo A actualiza i + 1 y el hilo B también actualiza i + 1.
Es posible que el valor de i no sea igual a 3 después de operaciones paralelas de dos hilos. Puede ser igual a 2. Debido a que A y B pueden obtener 1 al actualizar la variable i. Este es un problema de atomicidad típico
. Hay varias formas de lograr la atomicidad en el subproceso múltiple. Una de ellas es agregar un bloqueo sincronizado.
A partir de JDK 1.5, el paquete Atomic se proporciona en el paquete JUC, que proporciona operaciones atómicas en estructuras de datos de uso común. Proporciona una forma simple, eficiente y segura para subprocesos de actualizar una variable.

Clases de operación atómica en JUC

Debido a la relación de tipos de variables, en JUC se proporcionan 12 clases de operaciones atómicas. Estas 12 categorías se pueden dividir en cuatro categorías

  • Tipos básicos de actualizaciones atómicas
    1. AtómicoBooleano
    2. AtomicInteger
    3. AtomicLong
  • Matriz de actualización atómica
    1. AtomicIntegerArray
    2. AtomicLongArray
    3. AtomicReferenceArray
  • Cotización de actualización atómica
    1. AtomicReference
    2. AtomicReferenceFieldUpdater
    3. AtomicMarkableReference (actualice el tipo de referencia con bits de marca)
  • Campo de actualización atómica
    1. AtomicIntegerFieldUpdater
    2. AtomicLongFieldUpdater
    3. AtomicStampedReference

Análisis del principio AtomicInteger

Análisis de los principales métodos de AtomicInteger

  • getAndIncrement
public final int getAndIncrement() {
    
    
    return unsafe.getAndAddInt(this, valueOffset, 1);
}

getAndIncrement en realidad llama al método proporcionado en la clase insegura. La
clase Insegura se mencionó anteriormente cuando analizamos AQS. Esta clase es equivalente a una puerta trasera, lo que permite a Java manipular directamente el espacio de memoria como un puntero en lenguaje C. Por supuesto, también trae algunos inconvenientes, es decir, el problema de los punteros. De hecho, esta clase se usa de muchas formas, además del paquete JUC, existen Netty, kafka, etc.

Esta clase proporciona muchas funciones, incluida la sincronización de múltiples subprocesos (monitorEnter), operación CAS (compareAndSwap), suspensión y recuperación de subprocesos (estacionamiento / desarmado), barrera de memoria (loadFence / storeFence) gestión de memoria (asignación de memoria, liberación de memoria, adquisición Dirección de memoria , etc.)

  • valueOffset
private static final long valueOffset;

static {
    
    
    try {
    
    
        valueOffset = unsafe.objectFieldOffset
            (AtomicInteger.class.getDeclaredField("value"));
    } catch (Exception ex) {
    
     throw new Error(ex); }
}

Obtenga el desplazamiento del valor actual en la memoria a través de unsafe.objectFieldOffset (), y luego obtenga el valor del valor de la memoria basado en este desplazamiento para compararlo con el valor actual para lograr un bloqueo optimista

  • getAndAdd jdk1.7 y jdk1.8 se implementan de diferentes maneras (getAndAddInt es un método en unsafe.class)
public final int getAndAddInt(Object var1, long var2, int var4) {
    
    
    int var5;
    do {
    
    
        var5 = this.getIntVolatile(var1, var2);
    } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

    return var5;
}

A través del ciclo do / while, incremento atómico basado en el bloqueo optimista de CAS. De hecho, la función del valor anterior Offset es obtener el valor actual de la memoria principal y compararlo con el valor esperado. Si son iguales, incrementar el valor y finalizar el ciclo.

  • obtener método
private volatile int value;

public final int get() {
    
    
    return value;
}

El método get solo necesita devolver directamente el valor del valor, donde el valor es modificado por Volatile para garantizar la visibilidad.


  • La implementación de otros métodos AtomicInteger es muy simple, por lo que podemos analizar rápidamente sus principios de implementación, por supuesto, además de los dos métodos que acabamos de analizar, existen otros. Por ejemplo, proporciona compareAndSet, lo que permite a los clientes implementar operaciones de bloqueo optimistas basadas en AtomicInteger
public final boolean compareAndSet(int expect, int update) {
    
    
    return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

Siguiente
: "Otras herramientas comunes de concurrencia de JUC" de JUC Learning (5)

Supongo que te gusta

Origin blog.csdn.net/nonage_bread/article/details/110933775
Recomendado
Clasificación