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.
- set (valor int): establece el valor dado
- get(): Obtiene el valor actual
- lazySet (valor int): eventualmente se establece en el valor dado
- compareAndSet(int expect, int update): Establece atómicamente el valor al valor actualizado dado si el valor actual == el valor esperado
- addAndGet (int delta): agrega atómicamente el valor dado al valor actual
- 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); } }
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); } }
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); } }
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