Knowledge Base
Inicio > Java > Threads
Threads

Qué es un thread y cómo funciona

Un thread de Java es un contexto de ejecución o un proceso ligero. Es un solo flujo secuencial de control dentro de un programa. El programador puede utilizar el mecanismo del thread de Java para ejecutar múltiples tareas simultáneamente.

 
La clase Thread y el método run()
  • La ayuda básica para los threads está en la clase java.lang.Thread. Proporciona un API de threads y todo su comportamiento genérico. Estos comportamientos incluyen arrancar, suspender, el funcionamiento, el rendimiento, y la obtención de prioridad.
  • El método run() proporciona al thread algo para hacer. Su código debe poner en funcionamiento el thread.
    Hay dos formas de crear un thread personalizado:
    • Creando subclases java.lang.Thread y sobreescribiendo el método run().
    • Implementando la interfaz java.lang.Runnable.
 
Thread Scheduling
  • Cuando decimos que los threads están funcionando concurrentemente, en la práctica puede que no sea así. En un ordenador con una sola CPU, los threads funcionan realmente uno a la vez dando una ilusión de la concurrencia.
  • La ejecución de múltiples threads en una sola CPU basada en un cierto algoritmo se llama thread scheduling.
  • Los thread scheduler mantienen una reserva de todos los threads preparados para arrancar.De acuerdo con el algoritmo fijo de prioridad, asigna la CPU libre a uno de estos threads.
 
Ciclo de vida de un Thread

El diagrama siguiente ilustra los varios estados que un thread puede tener durante el transcurso de su vida y las llamadas de los método que causan la transición a otro estado.

Ready-to-run

Un thread comienza su ciclo vida con una llamada al método start(). Por ejemplo:

MyThread aThread = new MyThread();
aThread.start();

Una llamada start() no provocará la ejecución inmediatamente del thread, sino la moverá a la reserva de threads, esperando su turno para ser escogido para la ejecución.El thread scheduling escoge uno de los thread preparados para arrancar de acuerdo con las prioridades del thread.

Running

El código del thread está siendo ejecutado activamente por el procesador. Funciona hasta que se intercambia, se bloquea, o cede voluntariamente su turno con este método estático

Thread.yield();

Observe que el yield() es un método estático. Incluso si es llamado en algún objeto del thread, provoca que la ejecución actual del thread ceda la CPU.

Waiting

Una llamada al método wait() de java.lang.Object provoca que el objeto actual del thread espere. El thread permanece en estado "waiting" hasta que algún otro thread invoque el notify() o el método del notifyAll() de este objeto. El thread actual debe poseer el monitor de este objeto para llamar al wait().

Sleeping

El Java thread se puede forzar a dormir(suspendido) durante un tiempo predefinido

Thread.sleep(milisegundos);
Thread.sleep(milisegundos, nanosegundos);

Observe que el metodo estático sleep() solo garantiza que el thread dormirá por un tiempo predefinido y que funcionará un cierto rato después que haya transcurrido dicho tiempo.
Por ejemplo, una llamada a sleep(60) provocará que la actual ejecución del thread duerma 60 milisegundos. Este thread estará en estado "ready-to-run" después de este tiempo. Estará en estado de "funcionamiento" solamente cuando el planificador lo escoja para la ejecución. Así podemos decir que el thread funcionará de nuevo después de los 60 milisegundos.

Blocked on I/O

Un thread de java puede incorporar este estado mientras espera datos del dispositivo del I/O. El thread se moverá a Ready-to-run(Listo-para-correr) después de que la condición de I/O cambie(por ejemplo la lectura de un octeto de datos).

Blocked on Synchronization

Un thread de java puede incorporar este estado mientras espera el bloqueo del objeto. El thread se moverá a Ready-to-run cuando se adquiera el bloqueo.

Dead

Un thread de java puede incorporar este estado cuando ha finalizado el trabajo. Puede también incorporar este estado si el thread es finalizado por un error irrecuperable.

 
Sincronización del Thread

Los problemas pueden ocurrir cuando dos threads están intentando acceder/modificar el mismo objeto. Para prevenir estos problemas, java utiliza monitores y la clave sincronizada para controlar el acceso a un objeto por el thread.

Monitor
  • Monitor es cualquier clase con código sincronizado en ella.
  • Monitor controla sus threads clientes usando los métodos wait() y notify() (o notifyAll()).
  • Los métodos del wait() y del notify() tienen que ser llamados en código sincronizado.
  • El monitor pide al thread del cliente esperar si no está disponible.
  • Normalmente una llamada al wait() es situada en un bucle. La condición del bucle prueba generalmente la disponibilidad del monitor. Después de esperar, el thread reanuda la ejecución desde el punto donde lo dejó.

Código sincronizado y bloqueos
  • Objeto bloqueo
    Cada objeto tiene un bloqueo. El bloqueo puede ser controlado por mas de un thread a la vez. Bloquea los controles de acceso al código sincronizado.
  • Cuando un thread al ejecutarse encuentra una declaración sincronizada, entra en estado bloqueado y espera hasta que adquiere el bloqueo del objeto. Después, ejecuta el bloque del código y libera el bloqueo. Mientras la ejecución de un thread posea el bloqueo, ningún otro thread podrá adquirir el bloqueo. Así los bloqueos y el mecanismo de la sincronización asegura la excepción apropiado del código en múltiple threading.
 
Prioridad del Thread

Una prioridad del thread se especifica con un número entero desde 1 (el más bajo) a 10 (el más alto), las constantes Thread.MIN_PRIORITY y Thread.MAX_PRIORITY pueden también ser utilizadas. Por defecto, el método del setPriority() fija la prioridad del thread a 5, que es el Thread.NORM_PRIORITY.

Thread aThread = Thread.currentThread();
int currentPriority;
currentPriority = aThread.getPriority();
aThread.setPriority( currentPriority + 1 );

Fijar prioridades puede siempre no tener el efecto deseado porque los esquemas de la priorización pueden ser implementadas de forma diferente o en distintas plataformas. Sin embargo, utilice prioridades más altas para los threads que bloquean con frecuencia (para I/O sleeping o waiting). Cambie la intensidad de la CPU de media a baja para evitar la caída del procesador.

 
Thread Deadlock

En múltiple threading, pueden ocurrir los siguientes problemas:

  • El deadlock o abrazada mortal ocurre cuando dos o más threads están intentando conseguir el control del mismo objeto, y cada uno tiene un bloqueo en otro recurso que ellos necesitan para continuar.
  • Por ejemplo, cuando el thread A está esperando para bloquear un objeto P mientras tiene bloqueado un Objeto Q y al mismo tiempo, el thread B tiene bloqueado un Objeto P y está esperando para bloquear un objeto Q, en ese momento ocurre un deadlock.
  • Observe que si el thread está llevando a cabo un bloqueo y va a un estado sleeping, no suelta el bloqueo. Sin embargo, cuando el thread entra en estado bloqueado, deja normalmente el bloqueo. Esto elimina potencialmente los deadlocks de los threads.
  • Java no proporciona ninguna mecanismos para la detección o el control de las situaciones de los deadlocks, así que el programador es responsable de evitarlos.