Thread es una parte de la ejecución, es decir, es una ruta de ejecución independiente en un programa. Un programa puede tener más de un subproceso, lo que plantea el concepto de subprocesos múltiples . Debemos usar la clase java.lang.Thread para usar un hilo para realizar una tarea específica. En este artículo, veamos la implementación de los hilos a través de un programa.
Cada vez que se ejecuta un programa, la JVM primero verifica la existencia del método «Principal». Si el método está presente, por defecto crea un subproceso y este subproceso se llama «subproceso principal» porque es responsable de la ejecución de las declaraciones que están presentes en el método principal. Un subproceso puede estar en varios estados que se analizan en este artículo .
Hay dos formas de crear un hilo. Están:
- Creando un objeto para la clase Thread.
- Mediante el uso de la interfaz ejecutable.
Creación de subprocesos mediante la ampliación de la clase Subproceso: creamos una clase que amplía la clase java.lang.Thread. Esta clase anula el método run() disponible en la clase Thread. Un hilo comienza su vida dentro del método run() . Creamos un objeto de la clase hilo y llamamos al método start() para iniciar la ejecución de un hilo. Start() invoca el método run() en el objeto del hilo. Veamos un ejemplo para encontrar el factorial usando el hilo:
Java
// Java program to find the factorial // of a number by the implementation // of threads using thread class class ThreadImplement extends Thread { static int fact = 1; // Overriding the run method // to find the factorial of // a number 5 public void run() { // Loop to compute the factorial for (int i = 1; i <= 5; i++) fact = fact * i; System.out.println(fact); } } // Class to create a thread and // compute the factorial public class GFG { public static void main(String[] args) { // Creating an object of the // thread class Thread t1 = new Thread(new ThreadImplement()); // Computing the above class t1.start(); } }
120
Creación de subprocesos mediante la implementación de la interfaz ejecutable: la clase de subproceso implementa la interfaz ejecutable y la interfaz ejecutable contiene solo el método run() . Hay cerca de 37 métodos presentes en la clase de subprocesos, pero comúnmente usamos 22. Todas las tareas que deben ser ejecutadas por el subproceso deben colocarse dentro del método run(), es decir, debemos anular el método run(). Para iniciar un hilo, debemos usar el método start() . Después de iniciar un hilo, este hilo ejecutará las declaraciones que están presentes en el método run() . Implementemos el mismo programa factorial usando la interfaz ejecutable:
Java
// Java program to find the factorial // of a number by the implementation // of threads using runnable interface class ThreadImplement implements Runnable { static int fact = 1; // Overriding the run method // to find the factorial of // a number 5 public void run() { // Loop to compute the factorial for (int i = 1; i <= 5; i++) fact = fact * i; System.out.println(fact); } } // Class to create a thread and // compute the factorial public class GFG { public static void main(String[] args) { // Creating an object of the // thread class Thread t1 = new Thread(new ThreadImplement()); // Computing the above class t1.start(); } }
120
Subprocesos múltiples en Java: en informática, el problema productor-consumidor (también conocido como problema del búfer acotado) es un ejemplo clásico de un problema de sincronización de procesos múltiples. El problema describe dos procesos, el productor y el consumidor, que comparten un búfer común de tamaño fijo que se utiliza como cola.
- El trabajo del productor es generar datos, ponerlos en el búfer y comenzar de nuevo.
- Al mismo tiempo, el consumidor consume los datos (es decir, los elimina del búfer), una pieza a la vez.
En este problema, necesitamos dos subprocesos, Subproceso t1 (produce los datos) y Subproceso t2 (consume los datos). Sin embargo, ambos subprocesos no deberían ejecutarse simultáneamente.
A continuación se muestra la implementación del problema productor-consumidor:
Java
// Java program to implement the // producer consumer's problem import java.lang.Thread; // Producer class which extends the // thread class Producer extends Thread { // Creating a string buffer StringBuffer buffer; boolean dp = false; // Initializing the string buffer Producer() { buffer = new StringBuffer(4); } // Overriding the run method public void run() { synchronized (buffer) { // Adding the data into the // buffer for (int i = 0; i < 4; i++) { try { buffer.append(i); System.out.println("Produced " + i); } catch (Exception e) { e.printStackTrace(); } } // Notifying the buffer System.out.println("Buffer is FUll"); buffer.notify(); } } } // Consumer class which extends // the thread class Consumer extends Thread { // Creating the object of the // producer class Producer p; // Assigning the object of the // producer class Consumer(Producer temp) { p = temp; } // Overriding the run method public void run() { // Controlling the access of the // buffer to the shared producer synchronized (p.buffer) { try { p.buffer.wait(); } catch (Exception e) { e.printStackTrace(); } // Printing the values of the string buffer // and consuming the buffer for (int i = 0; i < 4; i++) { System.out.print(p.buffer.charAt(i) + " "); } System.out.println("\nBuffer is Empty"); } } } // Main class to implement the // Producer Consumer problem class GFG { public static void main(String args[]) { // Initially, there needs to be some data // in order to consume the data. So, // Producer object is created first Producer p = new Producer(); // Sending this producer object // into the consumer Consumer c = new Consumer(p); Thread t1 = new Thread(p); Thread t2 = new Thread(c); // Since from the producer object, // we have already produced the data. // So, we start by consuming it. t2.start(); t1.start(); } }
Produced 0 Produced 1 Produced 2 Produced 3 Buffer is FUll 0 1 2 3 Buffer is Empty
Problema del consumidor del productor sin sincronización: el código anterior es ineficiente porque los recursos de la CPU no se utilizan de manera eficiente. Los subprocesos están esperando el búfer en el estado de espera. En lugar de esto, podemos utilizar estos subprocesos de manera eficiente finalizándolos y volviéndolos a crear. Eso es:
- Creamos un hilo para producir los datos.
- Una vez que el búfer esté lleno, terminaremos ese hilo.
- Cree otro subproceso para consumir los datos (en este punto, el subproceso productor está muerto).
- Una vez que el búfer está vacío, el subproceso del consumidor termina y el subproceso del productor se crea y produce los datos (en este punto, el subproceso del consumidor está muerto).
A continuación se muestra la implementación del enfoque anterior:
Java
// Java program to implement the // producer consumer's problem // without using synchronization import java.lang.Thread; // Producer class which extends the // thread class Producer extends Thread { // Creating a string buffer StringBuffer buffer; // Initializing the string buffer Producer() { buffer = new StringBuffer(4); } // Overriding the run method public void run() { // Loop to add data into the // buffer for (int i = 0; i < 4; i++) { try { buffer.append(i); System.out.println("Produced " + i); } catch (Exception e) { // Exception is returned when // the buffer is not accessible e.printStackTrace(); } } System.out.println("Buffer is FUll"); // Creating a consumer object after // execution of the above method. // Here, this keyword refers to // the current object of the // producer. This object is passed // into the consumer to access the // created buffer Consumer c = new Consumer(this); } } // Consumer class which extends // the thread class Consumer extends Thread { Producer p; Thread t2; // Constructor to get the // producer object Consumer(Producer temp) { p = temp; // Creating a new thread for // the object t2 = new Thread(this); t2.start(); } // Overriding the run method public void run() { try { // Printing the string buffer and // consuming it for (int i = 0; i < 4; i++) { System.out.print(p.buffer.charAt(i) + " "); } } catch (Exception e) { e.printStackTrace(); } System.out.println("\nBuffer is Empty"); } } // Main class to implement the // Producer Consumer problem class Efficiency { public static void main(String args[]) { // Producer object is created and // passed into the thread. Producer p = new Producer(); Thread t1 = new Thread(p); // Here, instead of the same // thread waiting, a new thread // is created in the constructor // of the consumer class t1.start(); } }
Produced 0 Produced 1 Produced 2 Produced 3 Buffer is FUll 0 1 2 3 Buffer is Empty
Problema del consumidor del productor modificado: el enfoque anterior se puede mejorar aún más porque el productor y el consumidor utilizan el mismo búfer. Entonces, en lugar de usar varios subprocesos, use un subproceso de modo que inicialmente, el búfer esté vacío y el subproceso que se creó actúe como productor. Una vez que el búfer está lleno, este subproceso actúa como consumidor y consume los datos. Sin embargo, tenemos que evitar el punto muerto.
A continuación se muestra la implementación del enfoque anterior:
Java
// Java program to implement the // producer consumer's problem // using single thread import java.lang.Thread; // Producer class which extends the // thread class Producer extends Thread { // Creating a string buffer StringBuffer buffer; // Variable to avoid the deadlock boolean dp = false; Thread t1; Producer() { // Initializing the buffer buffer = new StringBuffer(4); // Creating a new thread with // the current object t1 = new Thread(this); t1.start(); } // Overriding the run method public void run() { // Loop to produce the // data and add it to // the buffer for (int i = 0; i < 4; i++) { try { buffer.append(i); System.out.println("Produced " + i); } catch (Exception e) { e.printStackTrace(); } } System.out.println("Buffer is FUll"); // Creating a consumer object // by passing the current // producer object Consumer c = new Consumer(this); // Reinitializing the thread // with the new value of the // consumer object t1 = new Thread(c); t1.start(); } } // Consumer class which extends // the thread class Consumer extends Thread { Producer p; // Constructor to initialize // with the producer object Consumer(Producer temp) { p = temp; } // Overriding the run method public void run() { try { // Loop to print the buffer and // consume the values for (int i = 0; i < 4; i++) { System.out.print(p.buffer.charAt(i) + " "); } } catch (Exception e) { e.printStackTrace(); } System.out.println("\nBuffer is Empty"); } } // Main class to implement the // Producer Consumer problem class GFG { public static void main(String args[]) { // Creating the object of the // producer Producer p = new Producer(); } }
Produced 0 Produced 1 Produced 2 Produced 3 Buffer is FUll 0 1 2 3 Buffer is Empty
Publicación traducida automáticamente
Artículo escrito por sahithchoudary123 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA