Variables atómicas en Java con ejemplos

En subprocesos múltiples , la entidad compartida conduce principalmente a un problema cuando se incorpora la concurrencia . Una entidad compartida, como un objeto mutable o una variable, puede cambiarse, lo que puede resultar en la inconsistencia del programa o la base de datos . Por lo tanto, se vuelve crucial tratar con la entidad compartida mientras se accede simultáneamente. Una variable atómica puede ser una de las alternativas en tal escenario. 

Java proporciona clases atómicas como AtomicInteger , AtomicLong , AtomicBoolean y AtomicReference . Los objetos de estas clases representan la variable atómica de int, long, boolean y object reference respectivamente. Estas clases contienen los siguientes métodos.

  1. set (valor int): establece el valor dado
  2. get(): Obtiene el valor actual
  3. lazySet (valor int): eventualmente se establece en el valor dado
  4. compareAndSet(int expect, int update): Establece atómicamente el valor al valor actualizado dado si el valor actual == el valor esperado
  5. addAndGet (int delta): agrega atómicamente el valor dado al valor actual
  6. decrementAndGet(): decrementa atómicamente en uno el valor actual

Ejemplo:  

// Atomic Variable
AtomicInteger var;

Necesidad de una variable atómica
Considere el siguiente ejemplo:

Java

class Counter extends Thread {
 
    // Counter Variable
    int count = 0;
 
    // method which would be called upon
    // the start of execution of a thread
    public void run()
    {
        int max = 1_000_00_000;
 
        // incrementing counter
        // total of max times
        for (int i = 0; i < max; i++) {
            count++;
        }
    }
}
 
public class UnSafeCounter {
    public static void main(String[] args)
        throws InterruptedException
    {
        // Instance of Counter Class
        Counter c = new Counter();
 
        // Defining Two different threads
        Thread first = new Thread(c, "First");
        Thread second = new Thread(c, "Second");
 
        // Threads start executing
        first.start();
        second.start();
 
        // main thread will wait for
        // both threads to get completed
        first.join();
        second.join();
 
        // Printing final value of count variable
        System.out.println(c.count);
    }
}
Producción: 

137754082

 

En un entorno de un solo subproceso, la clase mencionada anteriormente solo dará el resultado esperado. Pero cuando se trata de un entorno de subprocesos múltiples, puede generar resultados inconsistentes. Sucede porque la actualización de «var» se realiza en tres pasos: lectura, actualización y escritura. Si dos o más subprocesos intentan actualizar el valor al mismo tiempo, es posible que no se actualice correctamente.

Este problema se puede resolver usando Bloqueo y Sincronización , pero no de manera eficiente. 

1. Usar analogía de bloqueo o sincronización: la sincronización o el bloqueo pueden resolver nuestro problema, pero comprometen la eficiencia del tiempo o el rendimiento. En primer lugar, exige que el programador de subprocesos y recursos controle el bloqueo. En segundo lugar, cuando varios subprocesos intentan adquirir un bloqueo, solo uno de ellos gana, el resto se suspende o bloquea. La suspensión o el bloqueo de subprocesos puede tener un gran impacto en el rendimiento.

Java

import java.io.*;
import java.util.concurrent.locks.*;
 
class Counter extends Thread {
 
    // Counter Variable
    int count = 0;
 
    // method which would be called upon
    // the start of execution of a thread
    public synchronized void run()
    {
 
        int max = 1_000_00_000;
 
        // incrementing counter total of max times
        for (int i = 0; i < max; i++) {
            count++;
        }
    }
}
 
public class SynchronizedCounter {
    public static void main(String[] args)
        throws InterruptedException
    {
        // Instance of Counter Class
        Counter c = new Counter();
 
        // Defining Two different threads
        Thread first = new Thread(c, "First");
        Thread second = new Thread(c, "Second");
 
        // Threads start executing
        first.start();
        second.start();
 
        // main thread will wait for both
        // threads to complete execution
        first.join();
        second.join();
 
        // Printing final value of count variable
        System.out.println(c.count);
    }
}
Producción: 

200000000

 

2. Usando la variable atómica: 

Java

import java.util.concurrent.atomic.AtomicInteger;
 
class Counter extends Thread {
 
    // Atomic counter Variable
    AtomicInteger count;
 
    // Constructor of class
    Counter()
    {
        count = new AtomicInteger();
    }
 
    // method which would be called upon
    // the start of execution of a thread
    public void run()
    {
 
        int max = 1_000_00_000;
 
        // incrementing counter total of max times
        for (int i = 0; i < max; i++) {
            count.addAndGet(1);
        }
    }
}
 
public class AtomicCounter {
    public static void main(String[] args)
        throws InterruptedException
    {
        // Instance of Counter Class
        Counter c = new Counter();
 
        // Defining Two different threads
        Thread first = new Thread(c, "First");
        Thread second = new Thread(c, "Second");
 
        // Threads start executing
        first.start();
        second.start();
 
        // main thread will wait for both
        // threads to complete execution
        first.join();
        second.join();
 
        // Printing final value of count variable
        System.out.println(c.count);
    }
}
Producción: 

200000000

 

Publicación traducida automáticamente

Artículo escrito por NiravTalaviya y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *