Programación multiproceso (6) Clase atómica

Clase atómica

1. Clasificación atómica

Las clases atómicas están básicamente en el paquete java.util.concurrent.atomic

1.1 Tipos básicos de átomos

  • AtómicoBooleano
  • AtomicInteger
  • AtomicLong

1.2 Tipos de matrices atómicas

  • AtomicIntegerArray
  • AtomicLongArray

1.3 Tipos de referencia atómica

  • AtomicReference
  • AtomicStampedReference

1.4 Tipos de atributos atómicos

  • AtomicLongFieldUpdater
  • AtomicIntegerFieldUpdater

2. Instancia no atómica

Código de prueba

public class Test {
    
    

    static Long totalCount = 0L;

    public static void main(String[] args) {
    
    

        int j = 0;
        while (j < 100) {
    
    
            totalCount = 0L;

            Thread thread1 = new Thread(new Runnable() {
    
    
                @Override
                public void run() {
    
    
                    for (int i = 0; i < 500; i++) {
    
    
                        totalCount++;
                    }
                }
            }, "线程1");


            Thread thread2 = new Thread(new Runnable() {
    
    
                @Override
                public void run() {
    
    
                    for (int i = 0; i < 500; i++) {
    
    
                        totalCount++;
                    }
                }
            }, "线程1");


            thread1.start();
            thread2.start();
            try {
    
    
                thread1.join();
                thread2.join();
                System.out.println("当前总数量为:" + totalCount);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            j++;
        }
    }
}

Resultados de la prueba

当前总数量为:884
当前总数量为:717
当前总数量为:563
当前总数量为:1000
当前总数量为:1000
当前总数量为:1000
当前总数量为:1000
当前总数量为:1000
当前总数量为:1000
当前总数量为:686
当前总数量为:1000
...

Conclusión: se puede observar que cuando las clases no atómicas son multiproceso, los resultados obtenidos no son los que queremos

3. Instancia de clase atómica

Código de prueba

public class Test {
    
    

   // static Long totalCount = 0L;

   static AtomicInteger totalCount;

    public static void main(String[] args) {
    
    

        int j = 0;
        while (j < 100) {
    
    
            //原子类,初始值为0
            totalCount =  new AtomicInteger(0);

            Thread thread1 = new Thread(new Runnable() {
    
    
                @Override
                public void run() {
    
    
                    for (int i = 0; i < 500; i++) {
    
    
                        //totalCount++;
                        totalCount.getAndIncrement();
                    }
                }
            }, "线程1");


            Thread thread2 = new Thread(new Runnable() {
    
    
                @Override
                public void run() {
    
    
                    for (int i = 0; i < 500; i++) {
    
    
                        //totalCount++;
                        totalCount.getAndIncrement();
                    }
                }
            }, "线程1");


            thread1.start();
            thread2.start();
            try {
    
    
                thread1.join();
                thread2.join();
               // System.out.println("当前总数量为:" + totalCount);
                System.out.println("当前总数量为:" + totalCount.get());
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            j++;
        }
    }
}

Resultados de la prueba

当前总数量为:1000
当前总数量为:1000
当前总数量为:1000
当前总数量为:1000
当前总数量为:1000
当前总数量为:1000
当前总数量为:1000
当前总数量为:1000
当前总数量为:1000
当前总数量为:1000
当前总数量为:1000
当前总数量为:1000
当前总数量为:1000

Conclusión: AtomicInteger puede garantizar la atomicidad de los datos en el caso de multiproceso

4. Métodos comunes de AtomicInteger

  • getAndIncrement se usa primero y luego se incrementa en 1, que es equivalente a n ++
  • getAndDecrement se usa primero y luego se reduce en 1, que es equivalente a n–
  • DecrementAndGet primero decrementar en 1, luego usar, equivalente a -n
  • incrementAndGet se incrementa en 1 y está en uso. Equivalente a ++ n
  • obtener Obtener el valor actual

4. Análisis del código fuente de AtomicInteger

Utilice getAndAddInt del método inseguro para incrementar automáticamente
esto: es el valor actual valor
Desplazamiento de la dirección de compensación, para ayudarlo a encontrar la dirección de n en el montón

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

getIntVolatile Obtiene el valor esperado directamente de la memoria a través de volatile: var5
var1: valor actual
var2: dirección offset
var5: valor esperado

compareAndSwapInt Realice la operación CAS
var1: valor actual
var2: desplazamiento de dirección
var4: intervalo de incremento
var5: valor esperado
Compare si var1 y var5 son iguales,
iguales, lo que significa que ningún hilo ha cambiado, valor actual (var1) = valor esperado (var5 ) + El intervalo de incremento (var4) devuelve verdadero
no es el mismo, significa que el hilo ha cambiado, el valor actual (var1) = valor esperado (var5) devuelve falso, inténtelo de nuevo

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;
    }

5. Problema de ABA

Porque

  1. El hilo 1 lee var1 = A en la memoria del hilo (pila),
  2. El hilo 2 cambia var1 a B y luego a A
  3. Cuando el hilo 1 obtiene el valor esperado var5, sigue siendo A, lo que está en línea con las expectativas, lo que resulta en que no se cambie el reembolso
  4. En realidad, se ha cambiado el hilo 2

6. Solución ABA

La solución es agregar una marca de tiempo o un número de versión a la variable. En este caso, si se cambia, la marca de tiempo o el número de versión cambiará, y se puede encontrar en CAS

AtomicStampedReference resuelve el problema de ABA
getReference obtiene el valor esperado
getStamp obtiene la marca de tiempo

Código de prueba

public class ABATest {
    
    

    private static AtomicStampedReference<Integer> totalCount;

    public static void main(String[] args) {
    
    

        int j = 0;
        while (j < 100) {
    
    
            //原子类,初始值为0
            totalCount = new AtomicStampedReference<>(0, 0);

            Thread thread1 = new Thread(new Runnable() {
    
    
                @Override
                public void run() {
    
    
                    for (int i = 0; i < 500; i++) {
    
    
                        //totalCount++;
                        Integer reference;
                        int stamp;
                        do {
    
    
                            reference = totalCount.getReference();
                            stamp = totalCount.getStamp();
                        } while (!totalCount.compareAndSet(reference, reference + 1, stamp, stamp + 1));
                    }
                }
            }, "线程1");


            Thread thread2 = new Thread(new Runnable() {
    
    
                @Override
                public void run() {
    
    
                    for (int i = 0; i < 500; i++) {
    
    
                        Integer reference;
                        int stamp;
                        do {
    
    
                            reference = totalCount.getReference();
                            stamp = totalCount.getStamp();
                        } while (!totalCount.compareAndSet(reference, reference + 1, stamp, stamp + 1));

                    }
                }
            }, "线程1");


            thread1.start();
            thread2.start();
            try {
    
    
                thread1.join();
                thread2.join();
                // System.out.println("当前总数量为:" + totalCount);
                System.out.println("当前总数量为:" + totalCount.getReference());
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            j++;
        }
    }
}


Resultados de la prueba

当前总数量为:1000
当前总数量为:1000
当前总数量为:1000
当前总数量为:1000
当前总数量为:1000
当前总数量为:1000
当前总数量为:1000
当前总数量为:1000
当前总数量为:1000
当前总数量为:1000

Supongo que te gusta

Origin blog.csdn.net/jinian2016/article/details/109702413
Recomendado
Clasificación