Interferencia de subprocesos y errores de consistencia de memoria en Java

Java permite subprocesos múltiples , lo que implica la ejecución simultánea de dos o más partes del programa. Mejora la utilización de la CPU al realizar múltiples tareas simultáneamente. Los subprocesos se comunican entre sí compartiendo referencias a objetos y variables miembro.
Cuando dos subprocesos acceden a la misma memoria compartida

Esta comunicación en multithreading puede provocar dos tipos de errores, si no se implementa correctamente:

  1. Interferencia de hilo
  2. Inconsistencia de la memoria

Error de interferencia de subprocesos

Cuando varios subprocesos comparten la misma memoria, existe la posibilidad de que dos o más subprocesos diferentes que realizan diferentes operaciones en los mismos datos se intercalen entre sí y creen datos inconsistentes en la memoria. Los subprocesos se intercalan cuando realizan operaciones con varios pasos y su secuencia de pasos se superpone. Esto se llama interferencia de hilo.

Incluso para una operación pequeña como incrementar o disminuir el valor de una variable (por ejemplo, i) usando la declaración i++ o i–, la máquina virtual realiza varios pasos de la siguiente manera:

  1. Recuperar el valor de i de la memoria
  2. Incrementar/Disminuir el valor de i en 1
  3. Guarde el nuevo valor incrementado/decrementado de i en la memoria

Si hay dos subprocesos A y B que operan en el mismo objeto, A realiza la operación de incremento y B realiza la operación de disminución al mismo tiempo, podría generar inconsistencias en los datos. Si el valor inicial de i es 10. El subproceso A lee el valor de i de la memoria como 10 e incrementa su valor a 11. Antes de que pueda almacenar el nuevo valor en la memoria, el subproceso B lee el valor de i de la memoria como 10, ya que la memoria aún no ha sido actualizada. Ahora, el subproceso B reduce el valor de i a 9. El nuevo valor en la memoria ahora sería 9 u 11, donde el valor esperado en realidad era 10. Cualquiera de los resultados del subproceso puede perderse y sobrescribirse por el otro o no podría no haber ningún error en absoluto. Al ser impredecibles, los errores de interferencia de subprocesos son difíciles de detectar y corregir.

Diagrama de secuencia para error de interferencia de hilo

Ejemplo:

// Java program to explain the
// concept of thread interference.
import java.io.*;
  
// Creating thread by creating the
// objects of that class
class SharedClass {
    static int i=10;
    void increment()
    {
        for(int j=0;j<50;j++)
        {
                // incrementing value of i 
            i=i+1;
            System.out.println("i after increment "+i);
        }
    }
    void decrement()
    {
        for(int j=0;j<50;j++)
        {
                // decrementing value of i 
            i=i-1;
            System.out.println("i after decrement "+i);
        }
    }
}
  
class GFG {
    public static void main(String[] args)
    {
        final SharedClass s1 = new SharedClass();
        Thread t1 = new Thread()
        {
            @Override
            public void run()
            {
                s1.increment();
            }
        };
        Thread t2 = new Thread()
        {
            @Override
            public void run()
            {
                s1.decrement();
            }
        };
        t1.start();
        t2.start();
    }
}

En el código anterior, la última línea del resultado esperado debe ser «i después del incremento de 10» o «i después del decremento de 10», pero el resultado real puede variar debido a la interferencia de los subprocesos. La interferencia de subprocesos es impredecible, intente ejecutar el código anterior varias veces para encontrar el error de interferencia de subprocesos en algunos casos. Las operaciones de entrelazado de hilos se verían evidentemente.

Cómo evitar el error de interferencia de
subprocesos La interferencia de subprocesos se puede evitar haciendo que el código sea seguro para subprocesos a través de:

Error de consistencia de memoria

En subprocesos múltiples, puede haber posibilidades de que los cambios realizados por un subproceso no sean visibles para los otros subprocesos y todos tengan vistas inconsistentes de los mismos datos compartidos. Esto se conoce como error de consistencia de la memoria.

La coherencia de la memoria es más un concepto basado en la arquitectura que en Java. Los accesos a la memoria principal pueden no ocurrir en el mismo orden en que la CPU los inició, especialmente para las operaciones de escritura que a menudo pasan por los búferes de escritura del hardware, por lo que la CPU no necesita esperarlas. Las CPU garantizan que el orden de las escrituras en una sola ubicación de memoria se mantenga desde la perspectiva de todas las CPU, incluso si las CPU perciben el tiempo de escritura de otras CPU de manera diferente al tiempo real. Esto a veces conduce a inconsistencias en la memoria debido a la falta de visibilidad de los datos correctos.

Diagrama de secuencia para error de consistencia de memoria

Cómo evitar errores de consistencia de la memoria Los errores de
consistencia de la memoria se pueden evitar estableciendo una relación de «sucede antes» . Esta relación garantiza que la operación de escritura en memoria realizada por un subproceso sea visible para una operación de lectura de cualquier otro subproceso en la misma memoria compartida.

Las siguientes acciones pueden crear una relación de suceso anterior:

  • Thread.start() : esta declaración hace que los efectos del código que llevaron a la creación del nuevo hilo sean visibles para el nuevo hilo.
  • Thread.join() : esta declaración hace que los efectos del código en el hilo sean visibles para el hilo que realizó la unión.

Diferencia entre interferencia de subprocesos y error de consistencia de memoria

Error de interferencia de hilo Error de consistencia de memoria
La interferencia de subprocesos se ocupa del intercalado del proceso de ejecución de dos subprocesos. La inconsistencia de la memoria tiene que ver con la visibilidad y se ocupa de la memoria del hardware.
La interferencia de subprocesos se puede evitar otorgando acceso exclusivo a los subprocesos, es decir, solo un subproceso a la vez debe acceder a la memoria compartida. Los errores de consistencia de la memoria se pueden tratar estableciendo una relación antes de que ocurra, que es simplemente una garantía de que las escrituras en la memoria de una declaración específica son visibles para otra declaración específica.

Publicación traducida automáticamente

Artículo escrito por Prashasti Baranwal 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 *