Para comprender, uno debe tener un conocimiento sólido de Java OOP , Java Multithreading y Java Interrupted-Exception . Si no, revíselos, ya que el título en sí mismo es una pura implementación de subprocesos múltiples.
Enfoques:
- enfoque de novato
- Enfoque de subprocesos múltiples
- Invocación de sincronización en el enfoque de subprocesos múltiples
Para entender, consideremos una ilustración para implementar el enfoque.
Ilustración:
Discutiremos la arquitectura del sistema de transacciones bancarias utilizando java. A lo largo de este editorial, lo tomaré de la mano y lo guiaré a través de todo el procedimiento de transacción y lo haré fácil de entender para que incluso pueda explicárselo a sus amigos. En aras de la simplicidad, hemos considerado una cuenta bancaria conjunta con 5 propietarios (Arnab, Monodwip, Mukta, Rinkel y Shubham) y el saldo inicial es de cien dólares ($100). Las transacciones de la cuenta se enumeran a continuación:
Nombre | Saldo ($) | Retiro ($) | Depósito ($) | Comentario | Saldo final ($) |
---|---|---|---|---|---|
Arnab | 100 | 20 |
Arnab ha retirado 20 Saldo después del retiro: 80 |
80 | |
Monodwip | 80 | 40 |
Monodwip retirado 40 Saldo después del retiro: 40 |
40 | |
Muktá | 40 | 35 |
Mukta depositó 35 Saldo después del depósito: 75 |
75 | |
Rinkel | 75 | 80 |
Rinkel no puedes retirar 80 tu saldo es: 75 |
75 | |
Shubham | 75 | 40 |
Shubham retirado 40 Saldo después del retiro: 35 |
35 |
Enfoque 1: enfoque de novato
Hemos declarado el método «retirar» y «depositar» dentro de la clase «Banco» y acceder a ellos desde la clase de controlador «GFG» creando un objeto «obj» de la clase Banco.
Ejemplo
Java
// Java Program to illustrate Rookie Approach // In Banking transaction system // Class 1 // Bank class // Defining the banking transaction class Bank { // Initial balance $100 int total = 100; // Money withdrawal method. Withdraw only if // total money greater than or equal to the money // requested for withdrawal // Method // To withdraw money void withdrawn(String name, int withdrawal) { if (total >= withdrawal) { System.out.println(name + " withdrawn " + withdrawal); total = total - withdrawal; System.out.println("Balance after withdrawal: " + total); // Making the thread sleep for 1 second after // each withdrawal // Try block to check for exceptions try { // Making thread t osleep for 1 second Thread.sleep(1000); } // Catch block to handle the exceptions catch (InterruptedException e) { // Display the exception along with line // number // using printStacktrace() method e.printStackTrace(); } } // If the money requested for withdrawal is greater // than the balance then deny transaction*/ else { // Print statements System.out.println(name + " you can not withdraw " + withdrawal); System.out.println("your balance is: " + total); // Making the thread sleep for 1 second after // each transaction failure // Try block to check for exceptions try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } // Method - to deposit money // Accept money whenever deposited void deposit(String name, int deposit) { System.out.println(name + " deposited " + deposit); total = total + deposit; System.out.println("Balance after deposit: " + total); // Making the thread sleep for 1 second after // each deposit try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } // Class 2 // main class class GFG { // Main driver method public static void main(String[] args) { // Declaring an object of Bank class and calling the // withdarwn and deposit methods with suitable // parameters // Creating object of class 1 inside main() Bank obj = new Bank(); // Custom input - Transactions obj.withdrawn("Arnab", 20); obj.withdrawn("Monodwip", 40); obj.deposit("Mukta", 35); obj.withdrawn("Rinkel", 80); obj.withdrawn("Shubham", 40); } }
Producción:
C:\Users\USER\Desktop\LearnCoding\MultiThreading>javac GFG.java C:\Users\USER\Desktop\LearnCoding\MultiThreading>java GFG Arnab withdrawn 20 Balance after withdrawal: 80 //After 1 Second Monodwip withdrawn 40 Balance after withdrawal: 40 //After 1 Second Mukta deposited 35 Balance after deposit: 75 //After 1 Second Rinkel you can not withdraw 80 your balance is: 75 //After 1 Second Shubham withdrawn 40 Balance after withdrawal: 35
Hay ciertas desventajas asociadas con el enfoque Rookie como se muestra a continuación:
Dos personas no pueden realizar transacciones al mismo tiempo, una debe esperar hasta que la primera finalice su transacción. Si el número de personas es grande, debemos esperar y esperar hasta que llegue nuestro turno. Para demostrar este problema, hicimos que el subproceso se suspendiera durante 3 segundos durante cada transacción en el video que se proporciona a continuación. En la vida real, llevaría mucho tiempo hacer que este enfoque no se pueda implementar en proyectos de transacciones reales.
Método 2: enfoque de subprocesos múltiples
¿Cómo pueden ayudar los subprocesos múltiples?
Los subprocesos múltiples permiten que diferentes subprocesos funcionen al mismo tiempo sin tener ninguna dependencia entre sí. Un gran grupo de subprocesos puede realizar una operación al mismo tiempo.
Ejemplo
Java
// Java Program to illustrate Multithreading Approach // In Banking transaction system // Class 1 // Helper class class Bank { // Initial custom balance int total = 100; // Money withdrawal method. Withdraw only if total money // greater than or equal to the money requested for // withdrawal void withdrawn(String name, int withdrawal) { if (total >= withdrawal) { System.out.println(name + " withdrawn " + withdrawal); total = total - withdrawal; System.out.println(total); // Making the thread sleep for 1 second after // each withdrawal // Try block to check for exceptions try { // Making thread to sleep for 1 second Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } // Else if the money requested for withdrawal is // greater than the balance then deny transaction else { System.out.println(name + " you can not withdraw " + withdrawal); System.out.println("your balance is: " + total); // Making the thread sleep for 1 second after // each transaction failure try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } // Method - To deposit money // Accepting money whenever deposited void deposit(String name, int deposit) { System.out.println(name + " deposited " + deposit); total = total + deposit; System.out.println("Balance after deposit: " + total); // Making the thread sleep for 1 second after // each deposit try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } // Method - Withdraw method // Called from ThreadWithdrawal class // using the object of Bank class passed // from the main() method class ThreadWithdrawal extends Thread { Bank object; String name; int dollar; // Constructor of this method ThreadWithdrawal(Bank ob, String name, int money) { this.object = ob; this.name = name; this.dollar = money; } // run() method for thread public void run() { object.withdrawn(name, dollar); } } // Deposit method is called from ThreadDeposit class // using the object of Bank class passed // from the main method class ThreadDeposit extends Thread { Bank object; String name; int dollar; ThreadDeposit(Bank ob, String name, int money) { // This keyword refers t ocurrent instance itself this.object = ob; this.name = name; this.dollar = money; } public void run() { object.deposit(name, dollar); } } // Class 2 // Main class class GFG { // Main driver method public static void main(String[] args) { // Declaring an object of Bank class and passing the // object along with other parameters to the // ThreadWithdrawal and ThreadDeposit class. This // will be required to call withdrawn and deposit // methods from those class // Creating an object of class1 Bank obj = new Bank(); ThreadWithdrawal t1 = new ThreadWithdrawal(obj, "Arnab", 20); ThreadWithdrawal t2 = new ThreadWithdrawal(obj, "Monodwip", 40); ThreadDeposit t3 = new ThreadDeposit(obj, "Mukta", 35); ThreadWithdrawal t4 = new ThreadWithdrawal(obj, "Rinkel", 80); ThreadWithdrawal t5 = new ThreadWithdrawal(obj, "Shubham", 40); // When a program calls the start() method, a new // thread is created and then the run() method is // executed. // Starting threads created above t1.start(); t2.start(); t3.start(); t4.start(); t5.start(); } }
Producción:
Ahora bien, hay ciertos problemas con el enfoque de subprocesos múltiples, como se indica a continuación:
Cuando varios subprocesos intentan realizar una operación en particular al mismo tiempo, existe la posibilidad de un resultado incorrecto, esto se debe a que todos los subprocesos están actualizando el mismo recurso a la vez. En la salida anterior, obtuvimos saldo en cifras negativas por la misma razón.
¿Cómo manejar esos casos en los que varias personas intentan acceder a la misma operación a la vez?
Si varios subprocesos acceden a un solo recurso a la vez, existe la posibilidad de una mala salida. Este fenómeno no deseado se define como carrera de datos.
Supongamos que tenemos $100 en nuestra cuenta bancaria conjunta. Para engañar al banquero, ambos podemos solicitar $100 simultáneamente a la vez. El sistema creará un objeto, asignará 2 hilos y los pasará al método de retiro. ¡Al final del proceso, ambos tendremos $100!
Para manejar este problema, los ingenieros idearon el concepto de sincronización.
Método 3: Incorporación de sincronización con subprocesos múltiples
La sincronización proporciona un bloqueo al objeto y declara un área sensible (métodos de retiro y depósito). Un objeto puede tener varios subprocesos, pero solo se puede acceder al área sensible mediante 1 subproceso a la vez. El planificador de subprocesos elige el orden de ejecución de los subprocesos. Como es un proceso aleatorio, la salida es diferente para cada interpretación.
¿Por qué deberíamos usar la sincronización estática?
Digamos que tenemos 5 clases de subprocesos con 1 objeto cada una. Cada objeto tiene múltiples hilos. ¡Ahora se accederá al área sensible por 5 subprocesos a la vez! Para manejar este problema, a los ingenieros se les ocurrió la idea de la sincronización estática. Proporcionamos un bloqueo a la clase. La clase seleccionará 1 objeto a la vez. El objeto a su vez elegirá 1 hilo y lo pasará por el área sensible.
¿La ejecución sincronizada de subprocesos múltiples es más lenta que la ejecución normal sin subprocesos múltiples?
No. La cantidad de tiempo que una tarea pasa esperando a otra se considera sobrecarga. En subprocesos múltiples sincronizados, este tiempo de sobrecarga se puede usar para realizar otro trabajo productivo hasta que el subproceso en espera obtenga la clave del programador de subprocesos para ingresar al área sincronizada. Por lo tanto, la sobrecarga sería mínima en el caso de la ejecución sincronizada de subprocesos múltiples, por lo que podemos esperar que sea más rápida.
Ejemplo
Java
// Java Program to illustrate Multithreading Approach // With Synchronization In Banking transaction system // Class 1 // Helper class class Bank { // Initial balance $100 static int total = 100; // Money withdrawal method. Withdraw only if total money // greater than or equal to the money requested for // withdrawal static synchronized void withdrawn(String name, int withdrawal) { if (total >= withdrawal) { System.out.println(name + " withdrawn " + withdrawal); total = total - withdrawal; System.out.println("Balance after withdrawal: " + total); /* Making the thread sleep for 1 second after each withdrawal.*/ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } // If the money requested for withdrawal is greater // than the balance then deny transaction else { System.out.println(name + " you can not withdraw " + withdrawal); System.out.println("your balance is: " + total); // Making the thread sleep for 1 second after // each transaction failure // Try block to check for exceptions try { // Making thread to sleep for 1 second Thread.sleep(1000); } // Catch bloc kto handle exceptions catch (InterruptedException e) { // Display the line number where exception // occurred // Using printStackTrace() method e.printStackTrace(); } } } // Method - Deposit method // Accepting money whenever deposited static synchronized void deposit(String name, int deposit) { System.out.println(name + " deposited " + deposit); total = total + deposit; System.out.println("Balance after deposit: " + total); // Making the thread sleep for 1 second // after each deposit // Try block to check for exceptions try { // Making thread to sleep for 1 second Thread.sleep(1000); } // Catch block to handle InterruptedException // exception catch (InterruptedException e) { e.printStackTrace(); } } } // Method - Withdraw // It is called from ThreadWithdrawal class using // the object of Bank class passed from the main method class ThreadWithdrawal extends Thread { // Attributes of this class Bank object; String name; int dollar; // Constructor of this class ThreadWithdrawal(Bank ob, String name, int money) { // This keyword refers to parent class this.object = ob; this.name = name; this.dollar = money; } // run() method for the thread public void run() { object.withdrawn(name, dollar); } } // Deposit method is called from ThreadDeposit class using // the object of Bank class passed from the main method*/ // Class 2 // Helper class extending Thread class class ThreadDeposit extends Thread { Bank object; String name; int dollar; ThreadDeposit(Bank ob, String name, int money) { this.object = ob; this.name = name; this.dollar = money; } public void run() { object.deposit(name, dollar); } } // Class 3 // Main class class GFG { // Main driver method public static void main(String[] args) { // Declaring an object of Bank class and passing the // object along with other parameters to the // ThreadWithdrawal and ThreadDeposit class. This // will be required to call withdrawn and deposit // methods from those class // Creating object of above class inside main() Bank obj = new Bank(); // Creating threads ThreadWithdrawal t1 = new ThreadWithdrawal(obj, "Arnab", 20); ThreadWithdrawal t2 = new ThreadWithdrawal(obj, "Monodwip", 40); ThreadDeposit t3 = new ThreadDeposit(obj, "Mukta", 35); ThreadWithdrawal t4 = new ThreadWithdrawal(obj, "Rinkel", 80); ThreadWithdrawal t5 = new ThreadWithdrawal(obj, "Shubham", 40); // When a program calls the start() method, a new // thread is created and then the run() method is // executed t1.start(); t2.start(); t3.start(); t4.start(); t5.start(); } }
Salida (Compilado e interpretado):
Salida (interpretada): Shubham y Monodwip no pudieron retirar dinero
C:\Users\USER\Desktop\Network Java>java GFG Arnab withdrawn 20 Balance after withdrawal: 80 Rinkel withdrawn 80 Balance after withdrawal: 0 Shubham you can not withdraw 40 your balance is: 0 Mukta deposited 35 Balance after deposit: 35 Monodwip you can not withdraw 40 your balance is: 35
Salida (interpretada): Rinkel no pudo retirar dinero.
C:\Users\USER\Desktop\Network Java>java GFG Arnab withdrawn 20 Balance after withdrawal: 80 Shubham withdrawn 40 Balance after withdrawal: 40 Monodwip withdrawn 40 Balance after withdrawal: 0 Mukta deposited 35 Balance after deposit: 35 Rinkel you can not withdraw 80 your balance is: 35
Salida (interpretada): Monodwip no pudo retirar dinero.
C:\Users\USER\Desktop\Network Java>java GFG Arnab withdrawn 20 Balance after withdrawal: 80 Rinkel withdrawn 80 Balance after withdrawal: 0 Shubham you can not withdraw 40 your balance is: 0 Monodwip you can not withdraw 40 your balance is: 0 Mukta deposited 35 Balance after deposit: 35
Nota: El planificador de subprocesos elige el orden de ejecución de los subprocesos. Como es un proceso aleatorio, la salida es diferente para cada interpretación.
Publicación traducida automáticamente
Artículo escrito por dattabikash505 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA