CodeGym /Cursos /All lectures for ES purposes /Problemas de subprocesos múltiples: acceso a un recurso c...

Problemas de subprocesos múltiples: acceso a un recurso compartido

All lectures for ES purposes
Nivel 1 , Lección 145
Disponible

"¡Hola, amigo! Ayer discutimos los beneficios y las ventajas de los subprocesos múltiples. Ahora es el momento de ver las desventajas. Y, desafortunadamente, no son pequeñas".

Anteriormente, vimos un programa como un conjunto de objetos que llaman a los métodos de los demás. Ahora todo se vuelve un poco más complicado. Un programa es más como un conjunto de objetos que tiene varios "pequeños robots" (hilos) que se arrastran a través de él y ejecutan los comandos contenidos en los métodos.

Esta nueva interpretación no cancela la primera. Todavía son objetos, y todavía llaman a los métodos de los demás. Pero tenemos que recordar que hay varios hilos, y cada hilo hace su propio trabajo o tarea.

Un programa es cada vez más complicado. Diferentes subprocesos cambian el estado de diferentes objetos en función de las tareas que realizan. Y pueden pisar los dedos de los pies unos a otros.

Pero lo peor sucede en el interior de la máquina Java. Como ya he dicho, la aparente simultaneidad de hilos se logra por el hecho de que el procesador cambia constantemente de un hilo a otro. Cambia a un subproceso, funciona durante 10 milisegundos, cambia al siguiente subproceso, funciona durante 10 milisegundos, y así sucesivamente. Y aquí radica el problema: estos cambios pueden ocurrir en los momentos más inoportunos. Considere este ejemplo:

Código del primer hilo Código del segundo hilo
System.out.print ("Nick is"); System.out.print (""); System.out.print ("15"); System.out.print (""); System.out.print ("years old");
System.out.println ();
System.out.print ("Lena is"); System.out.print (""); System.out.print ("21"); System.out.print (""); System.out.print ("years old");
System.out.println ();
Lo que esperábamos que se mostrara
Nick tiene 15 años
Lena tiene 21 años
Ejecución de código real Código del primer hilo Código del segundo hilo
System.out.print ("Nick is");
System.out.print ("Lena is"); System.out.print (" ");
System.out.print (" "); System.out.print ("15");
System.out.print ("21"); System.out.print (" ");
System.out.print (" "); System.out.print ("years old"); System.out.println ();
System.out.print ("years old"); System.out.println ();
System.out.print ("Nick is");
//other thread is running
//other thread is running
System.out.print (" "); System.out.print ("15"); //other thread is running
//other thread is running
System.out.print (" "); System.out.print ("years old"); System.out.println ();
//other thread is running
//other thread is running
//other thread is running
System.out.print ("Lena is"); System.out.print (" ");
//other thread is running
//other thread is running
System.out.print ("21"); System.out.print (" ");
//other thread is running
//other thread is running
//other thread is running
System.out.print ("years old"); System.out.println ();
Lo que realmente se muestra
Nick es  Lena tiene   15  21  años
años

Y aquí hay otro ejemplo:

Código Descripción
class MyClass
{
private String name1 = "Ally";
private String name2 = "Lena";
public void swap()
{
String s = name1;
name1 = name2;
name2 = s;
}
}
El método de intercambio swapde los valores de las variables name1y name2.

¿Qué podría pasar si se llama desde dos subprocesos al mismo tiempo?

Ejecución de código real Código del primer hilo Código del segundo hilo
String s1 = name1; //Ally
name1 = name2; //Lena
String s2 = name1; //Lena(!)
name1 = name2; //Lena
name2 = s1; //Ally
name2 = s2; //Lena
String s1 = name1; name1 = name2;
//other thread is running
//other thread is running
name2 = s1;
//other thread is running
//other thread is running
//other thread is running
String s2 = name1; name1 = name2;
//other thread is running
name2 = s2;
La línea de fondo
Ambas variables tienen el valor «Lena».
El objeto «Ally» no lo logró. Esta perdido.

"¡¿Quién habría adivinado que errores como este son posibles con una operación de asignación tan simple?!"

"Sí, este problema tiene solución. Pero hablaremos de esto un poco más tarde, tengo la garganta seca".

Comentarios (2)
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION
Antonio Lopez Nivel 81 Expert
5 noviembre 2023
Ejercicio "deadlock" visto en la sesion(parte 1):

public class BankAccount {
    private int balance;

    public BankAccount(int balance) {
        this.balance = balance;
    }

    public synchronized void transfer(int amount, BankAccount toAccount) {
        if (balance >= amount) {
            balance -= amount;
            toAccount.balance += amount;
        }
    }

    public int getBalance() {
        return balance;
    }
}

public class BankTransfer {
    public static void main(String[] args) {
        // Crear dos cuentas bancarias
        BankAccount abcAccount = new BankAccount(1000);
        BankAccount xyzAccount = new BankAccount(500);

 
Antonio Lopez Nivel 81 Expert
5 noviembre 2023
Ejercicio :"deadlock" visto en la sesion (parte 2):


       // Crear dos hilos para realizar las transferencias
        Thread thread1 = new Thread(() -> {
            // Leer los balances actuales de las cuentas
            int montoActualABC = abcAccount.getBalance();
            int montoActualXYZ = xyzAccount.getBalance();

            // Calcular los nuevos balances de las cuentas
            int montoNuevoABC = montoActualABC + 200;
            int montoNuevoXYZ = montoActualXYZ - 200;

            // Escribir los nuevos balances de las cuentas
            abcAccount.transfer(200, xyzAccount);
        });

        Thread thread2 = new Thread(() -> {
            // Leer los balances actuales de las cuentas
            int montoActualABC = abcAccount.getBalance();
            int montoActualOOO = 600;

            // Calcular los nuevos balances de las cuentas
            int montoNuevoABC = montoActualABC + 300;
            int montoNuevoOOO = montoActualOOO - 300;

            // Escribir los nuevos balances de las cuentas
            abcAccount.transfer(300, new BankAccount(montoNuevoOOO));
        });

        // Iniciar los dos hilos
        thread1.start();
        thread2.start();

        // Esperar a que los dos hilos terminen
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // Imprimir los balances finales de las cuentas
        System.out.println("El balance final de la cuenta ABC es: " + abcAccount.getBalance());
        System.out.println("El balance final de la cuenta XYZ es: " + xyzAccount.getBalance());
    }
}