Professional Documents
Culture Documents
Cuando un thread est en este estado, es slo un objeto Thread vaco o nulo. No se han
asignado recursos del sistema todava para el thread. As, cuando un thread est en este
estado, lo nico que se puede hacer es arrancarlo con start().
Listo: Cuando se invoca el mtodo start() del hilo, se dice que est en estado listo. El
mtodo se arranca con la siguiente instruccin, para el caso del hilo miHilo: miHilo.start();
Ejecutable: cuando el mtodo start() se ejecuta, crea los recursos del sistema
necesarios para ejecutar el thread, programa el thread para Programacin de Hilos: Ciclo
de vida de un hilo 12 5 ejecutarse, y llama al mtodo run() del thread que se ejecuta en
forma secuencial. En este punto el thread est en el estado ejecutable. Se denomina as
puesto que todava no ha empezado a ejecutarse.
En ejecucin: Un hilo en estado de listo de la ms alta prioridad, pasa al estado de
ejecucin, cuando se le asignan los recursos de un procesador, o sea cuando inicia su
ejecucin. Aqu el thread est en ejecucin.Cada hilo tiene su prioridad, hilos con alta
prioridad se ejecutan preferencialmente sobre los hilos de baja prioridad.
No ejecutable: Un hilo contina la ejecucin de su mtodo run(), hasta que pasa al
estado de no ejecutable originado cuando ocurre alguno de los siguientes cuatro eventos:
Se invoca a su mtodo sleep().
Se invoca a su mtodo suspend().
El thread utiliza su mtodo wait() para esperar una condicin variable.
El thread est bloqueado durante una solicitud de entrada/salida. Por ejemplo, en el
siguiente fragmento de codigo se pone a dormir
miHilo durante 10 segundos (10.000 milisegundos):
Thread miHilo = new MiClaseThread();
miHilo.start();
try {
miHilo.sleep(10000);
} catch (InterruptedException e){}
Durante los 10 segundos que miHilo est dormido, incluso si el proceso se vuelve
disponible, miHilo no se ejecuta. Despus de 10 segundos, miHilo se convierte en
"Ejecutable" de nuevo y, si el procesador est disponible se ejecuta. Para cada entrada en
el estado "No Ejecutable", existe una ruta de escape distinto y especfico que devuelve el
thread al estado "Ejecutable". Por ejemplo, si un thread ha sido puesto a dormir durante
un cierto nmero de milisegundos deben pasar esos milisegundos antes de volverse
"Ejecutable" de nuevo. La siguiente es una secuencia de las acciones a realizar para cada
entrada en el estado "No Ejecutable":
Programacin de Hilos: Ciclo de vida de un hilo 12 - 6
Si se ha puesto a dormir un hilo, deben pasar el nmero de milisegundos especificados en
sleep().
Si se ha suspendido un hilo, se debe llamar a su mtodo resume().
Si un hilo est esperando una condicin variable, siempre que el objeto propietario de la
variable renuncie mediante notify() o notifyAll().
Si un hilo est bloqueado durante la I/O, cuando se complete la I/O.
Muerto: Un hilo pasa al estado de muerto cuando se termina su mtodo run(), o cuando
se ha invocado su mtodo stop(). En algn momento el sistema dispondr entonces del
hilo muerto. Un hilo puede morir de dos formas:
Muerte natural: se produce cuando su mtodo run() sale normalmente. Por ejemplo, el
bucle while en este mtodo es un bucle que itera 100 veces y luego sale. Por tanto el hilo
morir naturalmente cuando se llegue al final de la iteracin, es decir se termina su
mtodo run().
public void run() {
int i = 0;
while (i < 100) {
i++;
System.out.println("i = " + i);
}
}
Por muerte provocada: en cualquier momento llamando a su mtodo stop(). El siguiente
cdigo crea y arranca miHilo luego lo pone a dormir durante 10 segundos. Cuando el
thread actual se despierta, se lo mata con miHilo.stop(). El mtodo stop() lanza un objeto
ThreadDeath hacia al hilo a eliminar. El thread moriri cuando reciba realmente la
excepcin ThreadDeath.
Thread miHilo = new MiClaseThread();
miHilo.start();
try {
Thread.currentThread().sleep(10000);
} catch (InterruptedException e){
}
miHilo.stop();
El mtodo stop() provoca una terminacin sbita del mtodo run() del hilo. Si el mtodo
run() estuviera realizando clculos sensibles, stop() podra dejar el programa en un estado
inconsistente. Normalmente, no se debera Programacin de Hilos: Ciclo de vida de un
hilo 12 7 llamar al mtodo stop() pero si se debera proporcionar una terminacin
educada como la seleccin de una bandera que indique que el mtodo run() debera salir.
El mtodo stop() se encuentra depreciado en la versin JDK1.2.1.
Bloqueado: un hilo se encuentra en el estado bloqueado cuando el hilo realiza una
solicitud de entrada/salida. Cuando termina la entrada/salida que estaba esperando, un
hilo bloqueado queda en el estado listo.
2.2.2 Prioridades de un hilo.
Aunque un programa utilice varios threads y aparentemente estos se ejecuten
simultneamente, el sistema ejecuta una sola instruccin cada vez (esto es
particularmente cierto en sistemas con una sola CPU), aunque realizado a velocidad
suficiente para proporcionar la ilusin de simultaneidad. El mecanismo por el cual un
sistema controla la ejecucin concurrente de procesos se llama planificacin (scheduling).
Java soporta un mecanismo simple denominado planificacin por prioridad fija (fixed
priority scheduling). Esto significa que la planificacin de los threads se realiza en base a
la prioridad relativa de un thread frente a las prioridades de otros.
La prioridad de un thread es un valor entero (cuanto mayor es el nmero, mayor es la
prioridad), que puede asignarse con el mtodo setPriority. Por defecto la prioridad de un
thread es igual a la del thread que lo creo. Cuando hay varios threads en condiciones de
ser ejecutados (estado runnable), la mquina virtual elige el thread que tiene una prioridad
mas alta, que se ejecutaran hasta que:
Se detiene voluntariamente o
Alguna condicin hace que el thread no sea ejecutable (runnable), como una
operacin de entrada/salida o, si el sistema operativo tiene planificacin por
divisin de tiempos (time slicing), cuando expira el tiempo asignado.
Si dos o ms threads estn listos para ejecutarse y tienen la misma prioridad, la mquina
virtual va cediendo control de forma cclica (round-robin).
El hecho de que un thread con una prioridad ms alta interrumpa a otro se denomina se
denomina 'planificacin con derecho preferente' (preemptive scheduling).
Cuando un thread entra en ejecucin y no cede voluntariamente el control para que
puedan ejecutarse otros threads, se dice que es un thread egosta (selfish thread).
Algunos Sistemas Operativos, como Windows, combaten estas actitudes con una
estrategia de planificacin por divisin de tiempos (time-slicing), que opera con threads de
igual prioridad que compiten por la CPU. En estas condiciones el Sistema Operativo
asigna tiempos a cada thread y va cediendo el control consecutivamente a todos los que
compiten por el control de la CPU, impidiendo que uno de ellos se apropie del sistema
durante un intervalo de tiempo prolongado.
Este mecanismo lo proporciona el sistema operativo, no Java.
DECLARACIN SYNCHRONIZED
La creacin del mtodo Synchronized dentro de las clases creadas por nosotros
mismos es fcil y eficiente sin embargo no trabaja en todos los casos. Por ejemplo,
podemos querer sincronizar el acceso a algn mtodo que no este modificado
por Synchronized ; esto ocurre cuando queremos utilizar una clase que no fue creada
por nosotros sino por un tercero, y no tenemos acceso al cdigo fuente.
La solucin para este problema es poner llamadas a los mtodos definidos por esa
clase dentro de un bloque Synchronized. La forma general de un bloque Synchronized
es:
synchronized (objeto){
//declaraciones para ser sincronizadas
}
Aqu objeto hace referencia al objeto que va a ser sincronizado. Un objeto sincronizado
asegura que una llamada a un mtodo, ocurra solo despus de que el hilo que llama ha
ingresado al monitor del objeto.
EJEMPLO:
/**
uso de synchronized en el control de accesos
*/
class SumArray {
private int sum;
synchronized int SumArray(int nums[]){
sum=0; //inicializa sum
for (int i=0;i<nums.length;i++){
sum= nums[i];
System.out.println ("Ejecucion total para" + Thread.currentThread().getName() +
" es " + sum);
try{
Thread.sleep(10); //permite el suicheo de tareas
}
catch (InterruptedException exc){
System.out.println ("Hilo principal interrumpido ");
}
}
return sum;
}
}
class MyThread implements Runnable{
Thread thrd;
static SumArray sa=new SumArray();
int a[];
int answer;
/ /contruye un nuevo hilo
MyThread(String name,int nums[]){
thrd= new Thread (this,name);
thrd.start(); //arranca el hilo
a= nums;
}
//inicia la ejecucion del nuevo hilo
public void run(){
int sum;
System.out.println ("Suma para " + thrd.getName() + " es " + answer);
System.out.println (thrd.getName() + "terminando");
}
}
class Sync{
public static void main (String[] args) {
int a[]={1,2,3,4,5};
MyThread mt1= new MyThread ("Hijo #1",a);
MyThread mt2= new MyThread ("Hijo #2",a);
}
}
El programa anterior crea 3 clases. La primera es SumArray que contiene el mtodo
SumArray (), que suma un arreglo entero. La segunda clase es MyThread, que utiliza un
objeto de tipo SumArray para obtener la suma de un arreglo entero. Finalmente, la clase
Sync crea dos hilos, y permite que ellos calculen la suma de un arreglo entero.
Dentro de sumArray (), se llama sleep() para permitir que ocurra un cambio de tarea,
pero de hecho no es posible. Porque sumArray () est sincronizada. Solamente un hilo a
la vez puede utilizarla. De modo que cuando el segundo hilo hijo comience su ejecucin,
no ingresa sumArray() hasta despus que el primer hilo hijo est terminado. Esto asegura
que se produzca el resultado correcto.
COMUNICACIN DE HILOS UTILIZANDO NOTIFY (), WAIT() Y NOTIFY ALL ()
Los mtodos wait (), notify () y notify all () son parte de todos los objetos porque
estn implementados por la clase Object. Estos mtodos slo pueden ser llamados desde
el interior de un mtodo Synchronized. A continuacin se presenta como se utilizan.
Cuando un hilo est temporalmente bloqueado para ejecucin, llama a wait (). Esto hace
que el hilo vaya a dormir y que el monitor para ese objeto se libere, permitiendo que otro
hilo utilice el objeto. Luego en otro punto, el hilo dormido despierta cuando algn otro hilo
ingresa al monitor, y llama a notify () o a notify All (). Un llamado a notify () reanuda el
hilo. Una llamada a notify All () reanuda todos los hilos de ms alta prioridad gana el
acceso al objeto.
A continuacin, se muestran varias formas de wait () definidas por Object:
La primera forma espera hasta que sea notificada. La segunda forma espera hasta que
sea notificada o hasta que expire el perodo de milsegundos. La tercera forma le permite
a usted especificar el perodo a aguardar en trminos de nanosegundos.
A continuacin, se muestran las formas generales de notify () y notify All ():
EJEMPLO:
Para comprender la necesidad y aplicacin de wait() y notify (), crearemos un
programa que simule el tic-tac de un reloj, mostrando las palabras "tic" y "tac" en la
pantalla. Para realizar esto, crearemos una clase llamada TickTock que contiene dos
mtodos: tick() y tock().
Paja ejecutar el reloj se crean dos hilos, uno que llama a tick () y otro, a tock (). El
objetivo es hacer que los dos hilos se ejecute de modo que el resultado del programa
presentes un "tic-tac" constante.
/* uso de wait () y notify () para crear un reloj de tarjeta. */
class TickTock {
synchronized void tick ( boolean running ) {
if ( !running ) { //para el reloj
notify ( ); // notifica una espera para el hilo
return:
}
System.out.println ( "Tic ");
notify ( ); // permite la ejecucin del tock ()
try {
wait ( ); // espera que tock ( ) se complete
}
catch ( InterruptedException exc ) {
System.out.println ( "del Hilo interrumpido ");
}
}
synchronized void tock ( boolean running ) {
if (!running) { //para el reloj
notify ( ); // notifica una espera para el hilo
return;
}
System.out.println ( "Toc");
notify ( );
try {
wait ( ); // espera que tick ( ) se complete
}
catch ( InterruotedException exc ) {
System.out.println ( "Hilo interrumpido");
}
}
}
class MyThread implements Runnable {
Thread thrd;
TickTock ttOb;
// construye un nuevo hilo
MyThread ( String name.TickTock tt ) {
thrd= new Thread ( this.name );
ttOb= tt;
thrd.start ( ); // arranca el hilo
}
//inicia la ejecucin del nuevo hilo
public void main ( ) { // El hilo comienza a ejecutarse aqu
if ( thrd.getName ( ).compareTo ( "Tick") == 0 ) {
for ( int i=0; i<5; i++ ) ttOb.tick ( true );
ttOb.tock ( false );
}
else {
for ( int i=0; i<5; i++ ) ttOb.tock ( true );
ttOb.tock ( false );
}
}
}
class ThreadCom {
public static void main ( String args [ ]) {
TickTock t1= new TickTock ( );
MyThread mt1= new MyThread ( "Tick",tt );
MyThread mt2= new MyThread ( "Tock",tt );
try {
mt1.thrd.join ( );
mt2.thrd.join ( );
} catch ( InterruptedException exc ) {
System.out.println ( "Procedimiento interrumpido ");
}
}
}
2.2.4
Aplicaciones.