You are on page 1of 9

Unidad 2 Concurrencia de hilos

2.1 Conceptos bsicos


2.1.1 Definicin de concurrencia.
La concurrencia es la propiedad de los sistemas que permiten que mltiples procesos
sean ejecutados al mismo tiempo, y que potencialmente puedan interactuar entre s, los
procesos concurrentes pueden ser ejecutados realmente de forma simultnea, slo
cuando cada uno es ejecutado en diferentes procesadores. En cambio, la concurrencia es
simulada si slo existe un procesador encargado de ejecutar los procesos concurrentes,
simulando la concurrencia, ocupndose de forma alternada en uno y otro proceso a
pequesimos intervalos de tiempo. De esta manera simula que se estn ejecutando a la
vez.
2.1.2 Definicin de hilos.
En sistemas operativos, un hilo de ejecucin, hebra o subproceso es la unidad de
procesamiento ms pequea que puede ser planificada por un sistema operativo.
La creacin de un nuevo hilo es una caracterstica que permite a una aplicacin realizar
varias tareas a la vez (concurrentemente). Los distintos hilos de ejecucin comparten una
serie de recursos tales como el espacio de memoria, los archivos abiertos, situacin de
autenticacin, etc. Esta tcnica permite simplificar el diseo de una aplicacin que debe
llevar a cabo distintas funciones simultneamente.
Un hilo es simplemente una tarea que puede ser ejecutada al mismo tiempo con otra
tarea.
Los hilos de ejecucin que comparten los mismos recursos, sumados a estos recursos,
son en conjunto conocidos como un proceso. El hecho de que los hilos de ejecucin de un
mismo proceso compartan los recursos hace que cualquiera de estos hilos pueda
modificar stos. Cuando un hilo modifica un dato en la memoria, los otros hilos acceden a
ese dato modificado inmediatamente.

2.2 Implementacin de hilos.


2.2.1 Estados de un hilo.
Un hilo tiene un ciclo de vida que va desde su creacin hasta su terminacin. Durante su
ciclo de vida cada uno de los hilos o tareas de una aplicacin puede estar en diferentes
estados, algunos de los cuales se indican a continuacin:
Nacido: Cuando se acaba de crear un hilo, se dice que est nacido, y contina en ese
estado hasta que se invoca el mtodo start() del hilo. La siguiente sentencia crea un
nuevo thread pero no lo arranca, por lo tanto deja el thread en el estado de nacido.
Thread miHilo = new MiClaseThread();

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:

Un thread con una prioridad ms alta est en condiciones de ser ejecutado


(runnable), o

El thread termina (termina su metodo run), o

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.

2.2.3 Sincronizacin de hilos.


Cuando se estn utilizando hilos mltiples,algunas veces es necesario coordinar las
actividades de dos o ms. El proceso por el cual se logra esto se llama sincronizacin. La
razn ms comn para la sincronizacin es cuando dos o mas hilos necesitan acceso a
un recurso compartido que slo puede ser utilizado por un hilo a la vez. Otra razn para
la sincronizacin es cuando un hilo est esperando un evento causado por otro hilo. En
este caso, debe de haber algn medio por el cual el primer hilo se mantenga en estado
suspendido hasta que el evento ocurra.
La sincronizacin esta soportada por la palabra clave synchronized y por unos
cuantos mtodos bien definidos que tienen todos los objetos.
USO DE MTODOS SYNCHRONIZED
Cuando se llama al mtodo Synchronized , el hilo que llama ingresa al monitor de
objeto, que entonces bloquea el objeto. Mientras esta bloqueado ningn otro hilo puede
ingresar al mtodo, ni ingresar algn otro mtodo sincronizado definido por el objeto.
Cuando el hilo retorna del mtodo, el monitor desbloquea el objeto permitiendo que sea
usado por el prximo hilo.
Los puntos clave de un mtodo sincronizado son:

Un mtodo sincronizado se crea precediendo su declaracin con synchronized.

Para cualquier objeto dado,una vez un mtodo sincronizado ha sido llamado se


bloquea el objeto, y los mtodos no sincronizados dentro del mismo objeto pueden
ser utilizados por otros hilos en ejecucin.

Otros hilos que traten de llamar un objeto sincronizado en uso ingresara en un


estado de espera, hasta que el objeto se desbloquea.

Cuando un hilo sale del mtodo sincronizado, el objeto se desbloquea.

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:

final void wait() throws InterruptedException

final void wait ( long milsegundos ) throws InterruptedException

final void wait ( long milisegundos, int nanosegundos ) throwsInterruptedException

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 ():

final void notify ()

final void notifyAll ()

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.

You might also like