Antes de hablar multihilo, hablemos de los hilos. Un hilo es una parte más pequeña y ligera de un proceso que puede ejecutarse simultáneamente con otras partes (otros hilos) del mismo proceso. Los subprocesos son independientes porque todos tienen una ruta de ejecución separada, por lo que si ocurre una excepción en un subproceso, no afecta la ejecución de otros subprocesos. Todos los subprocesos de un proceso comparten una memoria común. El proceso de ejecutar varios subprocesos simultáneamente se conoce como subprocesos múltiples.

Resumamos la discusión en puntos:
1. El propósito principal del subproceso múltiple es proporcionar la ejecución simultánea de dos o más partes de un programa para aprovechar al máximo el tiempo de la CPU. Un programa multiproceso contiene dos o más partes que pueden ejecutarse simultáneamente. Cada una de estas partes de un programa se llama hilo.

2. Los subprocesos son subprocesos ligeros, comparten un espacio de memoria común. En el entorno multiproceso, los programas que aprovechan el multiproceso utilizan el tiempo máximo de CPU para minimizar el tiempo de inactividad.

3. Un hilo puede estar en uno de los siguientes estados:
NUEVO: un hilo que aún no ha comenzado se encuentra en este estado.
EJECUTABLE: Un subproceso que se ejecuta en la máquina virtual Java se encuentra en este estado.
BLOQUEADO: un subproceso bloqueado en espera de un bloqueo de monitor se encuentra en este estado.
ESPERANDO: un subproceso que espera indefinidamente a que otro subproceso realice una determinada acción se encuentra en este estado.
TIMED_WAITING: un subproceso que espera que otro subproceso realice una acción hasta un tiempo de espera especificado se encuentra en este estado.
TERMINADO: un subproceso terminado está en este estado.
Un hilo solo puede estar en un estado en un momento dado.

Obtenga más información sobre los estados de los hilos en este enlace: Ciclo de vida de los cables

Multitarea vs multihilo vs multiprocesamiento vs procesamiento paralelo

Si es nuevo en Java, puede confundirse con estos términos, ya que se utilizan con bastante frecuencia cuando se trata de subprocesos múltiples. Hablemos brevemente.

Multitarea: La capacidad de realizar más de una tarea al mismo tiempo se conoce como multitarea.

Subprocesos múltiples: Ya hemos hablado de esto. Es un proceso de ejecución simultánea de múltiples subprocesos. El subproceso múltiple también se conoce como multitarea basada en subprocesos.

Multiprocesamiento: Esto es lo mismo que la multitarea, sin embargo, varias CPU están involucradas en el multiprocesamiento. Por otro lado, una CPU está involucrada en la multitarea.

leer  ¿Cuál es la diferencia entre un proceso y un hilo en Java?

Procesamiento en paralelo: Se refiere al uso de varias CPU en un solo sistema informático.

Creando un hilo en Java

Hay dos formas de crear un hilo en Java:
1) Ampliación de la clase Thread.
2) Implementación de la interfaz Runnable.

Antes de comenzar con los programas (código) para crear subprocesos, echemos un vistazo a estos métodos de la clase Thread. Hemos utilizado algunos de estos métodos en el siguiente ejemplo.

  • getName(): Se usa para obtener el nombre de un hilo
  • getPriority(): Obtiene la prioridad de un hilo
  • isAlive(): Determina si un hilo aún se está ejecutando
  • join(): Espere a que termine un hilo
  • run(): Punto de entrada para el hilo
  • sleep()– Pausa un hilo por un período de tiempo
  • start(): inicia un hilo llamando a su método run ()

Método 1: crear subprocesos extendiendo la clase Thread

Ejemplo 1:

class MultithreadingDemo extends Thread{  
  public void run(){  
    System.out.println("My thread is in running state.");  
  }   
  public static void main(String args[]){  
     MultithreadingDemo obj=new MultithreadingDemo();   
     obj.start();  
  }  
}

Producción:

My thread is in running state.

Ejemplo 2:

class Count extends Thread
{
   Count()
   {
     super("my extending thread");
     System.out.println("my thread created" + this);
     start();
   }
   public void run()
   {
     try
     {
        for (int i=0 ;i<10;i++)
        {
           System.out.println("Printing the count " + i);
           Thread.sleep(1000);
        }
     }
     catch(InterruptedException e)
     {
        System.out.println("my thread interrupted");
     }
     System.out.println("My thread run is over" );
   }
}
class ExtendingExample
{
   public static void main(String args[])
   {
      Count cnt = new Count();
      try
      {
         while(cnt.isAlive())
         {
           System.out.println("Main thread will be alive till the child thread is live");
           Thread.sleep(1500);
         }
      }
      catch(InterruptedException e)
      {
        System.out.println("Main thread interrupted");
      }
      System.out.println("Main thread's run is over" );
   }
}

Producción:

my thread createdThread[my runnable thread,5,main]
Main thread will be alive till the child thread is live
Printing the count 0
Printing the count 1
Main thread will be alive till the child thread is live
Printing the count 2
Main thread will be alive till the child thread is live
Printing the count 3
Printing the count 4
Main thread will be alive till the child thread is live
Printing the count 5
Main thread will be alive till the child thread is live
Printing the count 6
Printing the count 7
Main thread will be alive till the child thread is live
Printing the count 8
Main thread will be alive till the child thread is live
Printing the count 9
mythread run is over
Main thread run is over

Método 2: crear subprocesos implementando la interfaz ejecutable

Un simple ejemplo

class MultithreadingDemo implements Runnable{  
  public void run(){  
    System.out.println("My thread is in running state.");  
  }   
  public static void main(String args[]){  
     MultithreadingDemo obj=new MultithreadingDemo();  
     Thread tobj =new Thread(obj);  
     tobj.start();  
 }  
}

Producción:

My thread is in running state.

Programa de ejemplo 2:

leer  Método Thread join () en Java con ejemplo

Mire el resultado de este programa e intente comprender lo que está sucediendo en este programa. Si comprende el uso de cada método de hilo, no debería enfrentar ningún problema al comprender este ejemplo.

class Count implements Runnable
{
   Thread mythread ;
   Count()
   { 
      mythread = new Thread(this, "my runnable thread");
      System.out.println("my thread created" + mythread);
      mythread.start();
   }
   public void run()
   {
      try
      {
        for (int i=0 ;i<10;i++)
        {
          System.out.println("Printing the count " + i);
          Thread.sleep(1000);
        }
     }
     catch(InterruptedException e)
     {
        System.out.println("my thread interrupted");
     }
     System.out.println("mythread run is over" );
   }
}
class RunnableExample
{
    public static void main(String args[])
    {
       Count cnt = new Count();
       try
       {
          while(cnt.mythread.isAlive())
          {
            System.out.println("Main thread will be alive till the child thread is live"); 
            Thread.sleep(1500);
          }
       }
       catch(InterruptedException e)
       {
          System.out.println("Main thread interrupted");
       }
       System.out.println("Main thread run is over" );
    }
}

Producción:

my thread createdThread[my runnable thread,5,main]
Main thread will be alive till the child thread is live
Printing the count 0
Printing the count 1
Main thread will be alive till the child thread is live
Printing the count 2
Main thread will be alive till the child thread is live
Printing the count 3
Printing the count 4
Main thread will be alive till the child thread is live
Printing the count 5
Main thread will be alive till the child thread is live
Printing the count 6
Printing the count 7
Main thread will be alive till the child thread is live
Printing the count 8
Main thread will be alive till the child thread is live
Printing the count 9
mythread run is over
Main thread run is over

Tarea prioritaria

  • Las prioridades de subprocesos son los números enteros que deciden cómo se debe tratar un subproceso en relación con el otro.
  • La prioridad del subproceso decide cuándo cambiar de un subproceso en ejecución a otro, el proceso se denomina cambio de contexto
  • Un subproceso puede liberar voluntariamente el control y el subproceso de mayor prioridad listo para ejecutarse recibe la CPU.
  • Un hilo puede ir precedido por un hilo de mayor prioridad independientemente de lo que esté haciendo el hilo de menor prioridad. Siempre que un hilo de mayor prioridad quiere ejecutarlo, lo hace.
  • Para establecer la prioridad del hilo setPriority() se utiliza el método que es un método de la clase Thread Clase.
  • En lugar de definir la prioridad en números enteros, podemos usar MIN_PRIORITY, NORM_PRIORITY o MAX_PRIORITY.

Métodos: isAlive () y join ()

  • En todas las situaciones prácticas, el hilo principal debe terminar último, de lo contrario los otros hilos que fueron generados por el hilo principal también terminarán.
  • Para saber si el hilo ha finalizado podemos llamar isAlive() en el hilo que devuelve verdadero si el hilo no está terminado.
  • Otra forma de lograr esto es usando join() método, este método cuando es llamado por el hilo principal hace que el hilo principal espere hasta el final del hilo secundario.
  • Estos métodos se definen en Thread clase.
  • También usamos el método isAlive () en los ejemplos anteriores.
leer  Ciclo de vida de subprocesos en java y programación de subprocesos

Sincronización

  • El subproceso múltiple introduce un comportamiento asincrónico en los programas. Si un hilo está escribiendo datos, otro hilo puede estar leyendo los mismos datos en ese momento. Esto podría causar inconsistencias.
  • Cuando dos o más subprocesos necesitan acceso a un recurso compartido, debe haber una forma de que el recurso solo sea utilizado por un recurso a la vez. El proceso de lograr esto se llama sincronización.
  • Para implementar el comportamiento sincrónico, Java tiene un método sincrónico. Una vez que un hilo está dentro de un método sincronizado, ningún otro hilo puede llamar a ningún otro método sincronizado en el mismo objeto. Todos los demás subprocesos esperan a que el primer subproceso salga del bloqueo sincronizado.
  • Cuando queremos sincronizar el acceso a objetos de una clase que no está diseñada para acceso multiproceso y el código del método al que se accede sincrónicamente no está disponible con nosotros, en este caso no podemos agregar el sincronizado a los métodos correspondientes. En java tenemos la solución para esto, poner las llamadas a los métodos (que deben estar sincronizados) definidos por esta clase dentro de un bloque sincronizado de la siguiente manera.
Synchronized(object)
{
    // statement to be synchronized
}

Comunicación entre hilos

Tenemos pocos métodos a través de los cuales los subprocesos de Java pueden comunicarse entre sí. Estos métodos son wait(), notify(), notifyAll(). Todos estos métodos solo se pueden llamar desde un método sincronizado.
1) Para comprender la sincronización, Java tiene un concepto de monitor. Se puede pensar en el monitor como una caja que solo puede contener un hilo. Una vez que un hilo ingresa al monitor, todos los demás hilos deben esperar hasta que ese hilo salga del monitor.
2) wait() le dice al hilo que llama que deje el monitor y se vaya a dormir hasta que otro hilo entre en el mismo monitor y llame notify().
3) notify() despierta el primer hilo que llamó wait() en el mismo objeto.
notifyAll() despierta todos los hilos que llamaron a wait () en el mismo objeto. El hilo con la prioridad más alta se ejecutará primero.

Referencias

  • La referencia completa de Java 2 por Herbert Schildt

Por avivcas

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *