Concurrencia de Java: descripción general

Java es un lenguaje de programación de múltiples subprocesos, lo que significa que podemos desarrollar un programa de múltiples subprocesos utilizando Java. Un programa de subprocesos múltiples contiene dos o más partes que pueden ejecutarse simultáneamente y cada parte puede manejar una tarea diferente al mismo tiempo haciendo un uso óptimo de los recursos disponibles especialmente cuando su computadora tiene múltiples CPU.

Por definición, la multitarea es cuando varios procesos comparten recursos de procesamiento comunes, como una CPU. El subproceso múltiple extiende la idea de la multitarea a aplicaciones en las que puede subdividir operaciones específicas dentro de una sola aplicación en subprocesos individuales. Cada uno de los subprocesos se puede ejecutar en paralelo. El sistema operativo divide el tiempo de procesamiento no solo entre diferentes aplicaciones, sino también entre cada hilo dentro de una aplicación.

El subproceso múltiple le permite escribir de una manera en la que pueden realizarse múltiples actividades simultáneamente en el mismo programa.

Ciclo de vida de un hilo

Un hilo pasa por varias etapas en su ciclo de vida. Por ejemplo, un hilo nace, se inicia, se ejecuta y luego muere. El siguiente diagrama muestra el ciclo de vida completo de un hilo.

Las siguientes son las etapas del ciclo de vida:

  • New- Un nuevo hilo comienza su ciclo de vida en el nuevo estado. Permanece en este estado hasta que el programa inicia el hilo. También se conoce comoborn thread.

  • Runnable- Después de que se inicia un hilo recién nacido, el hilo se vuelve ejecutable. Se considera que un subproceso en este estado está ejecutando su tarea.

  • Waiting- A veces, un hilo pasa al estado de espera mientras el hilo espera a que otro hilo realice una tarea. Un subproceso regresa al estado ejecutable solo cuando otro subproceso indica al subproceso en espera que continúe ejecutándose.

  • Timed Waiting- Un subproceso ejecutable puede entrar en el estado de espera temporizada durante un intervalo de tiempo especificado. Un hilo en este estado vuelve al estado ejecutable cuando ese intervalo de tiempo expira o cuando ocurre el evento que está esperando.

  • Terminated (Dead) - Un subproceso ejecutable entra en el estado terminado cuando completa su tarea o termina.

Prioridades de hilo

Cada hilo de Java tiene una prioridad que ayuda al sistema operativo a determinar el orden en el que se programan los hilos.

Las prioridades de los hilos de Java están en el rango entre MIN_PRIORITY (una constante de 1) y MAX_PRIORITY (una constante de 10). De forma predeterminada, cada hilo tiene prioridad NORM_PRIORITY (una constante de 5).

Los subprocesos con mayor prioridad son más importantes para un programa y deben asignarse tiempo de procesador antes que los subprocesos de menor prioridad. Sin embargo, las prioridades de los subprocesos no pueden garantizar el orden en el que se ejecutan los subprocesos y dependen en gran medida de la plataforma.

Crear un hilo implementando una interfaz ejecutable

Si su clase está destinada a ejecutarse como un hilo, puede lograrlo implementando un Runnableinterfaz. Deberá seguir tres pasos básicos:

Paso 1

Como primer paso, debe implementar un método run () proporcionado por un Runnableinterfaz. Este método proporciona un punto de entrada para el hilo y pondrá su lógica empresarial completa dentro de este método. A continuación se muestra una sintaxis simple del método run ():

public void run( )

Paso 2

Como segundo paso, creará una instancia Thread objeto usando el siguiente constructor -

Thread(Runnable threadObj, String threadName);

Donde, threadObj es una instancia de una clase que implementa elRunnable interfaz y threadName es el nombre que se le da al nuevo hilo.

Paso 3

Una vez que se crea un objeto Thread, puede iniciarlo llamando start()método, que ejecuta una llamada al método run (). A continuación se muestra una sintaxis simple del método start ():

void start();

Example

Aquí hay un ejemplo que crea un nuevo hilo y comienza a ejecutarlo:

class RunnableDemo implements Runnable {
   private Thread t;
   private String threadName;

   RunnableDemo(String name) {
      threadName = name;
      System.out.println("Creating " +  threadName );
   }
   
   public void run() {
      System.out.println("Running " +  threadName );
      
      try {
      
         for(int i = 4; i > 0; i--) {
            System.out.println("Thread: " + threadName + ", " + i);
            
            // Let the thread sleep for a while.
            Thread.sleep(50);
         }
      } catch (InterruptedException e) {
         System.out.println("Thread " +  threadName + " interrupted.");
      }
      System.out.println("Thread " +  threadName + " exiting.");
   }
   
   public void start () {
      System.out.println("Starting " +  threadName );
      
      if (t == null) {
         t = new Thread (this, threadName);
         t.start ();
      }
   }
}

public class TestThread {

   public static void main(String args[]) {
      RunnableDemo R1 = new RunnableDemo("Thread-1");
      R1.start();
      
      RunnableDemo R2 = new RunnableDemo("Thread-2");
      R2.start();
   }   
}

Esto producirá el siguiente resultado:

Output

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.

Crear un hilo ampliando una clase de hilo

La segunda forma de crear un hilo es crear una nueva clase que se extienda Threadclase usando los siguientes dos sencillos pasos. Este enfoque proporciona más flexibilidad en el manejo de varios subprocesos creados con los métodos disponibles en la clase Thread.

Paso 1

Necesitarás anular run( )método disponible en la clase Thread. Este método proporciona un punto de entrada para el hilo y pondrá su lógica empresarial completa dentro de este método. A continuación se muestra una sintaxis simple del método run ():

public void run( )

Paso 2

Una vez que se crea el objeto Thread, puede iniciarlo llamando start()método, que ejecuta una llamada al método run (). A continuación se muestra una sintaxis simple del método start ():

void start( );

Example

Aquí está el programa anterior reescrito para extender el hilo:

class ThreadDemo extends Thread {
   private Thread t;
   private String threadName;
   
   ThreadDemo(String name) {
      threadName = name;
      System.out.println("Creating " +  threadName );
   }
   
   public void run() {
      System.out.println("Running " +  threadName );
      
      try {

         for(int i = 4; i > 0; i--) {
            System.out.println("Thread: " + threadName + ", " + i);
            
            // Let the thread sleep for a while.
            Thread.sleep(50);
         }
      } catch (InterruptedException e) {
         System.out.println("Thread " +  threadName + " interrupted.");
      }
      System.out.println("Thread " +  threadName + " exiting.");
   }
   
   public void start () {
      System.out.println("Starting " +  threadName );
      
      if (t == null) {
         t = new Thread (this, threadName);
         t.start ();
      }
   }
}

public class TestThread {

   public static void main(String args[]) {
      ThreadDemo T1 = new ThreadDemo("Thread-1");
      T1.start();
      
      ThreadDemo T2 = new ThreadDemo("Thread-2");
      T2.start();
   }   
}

Esto producirá el siguiente resultado:

Output

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.