Vous êtes sur la page 1sur 9

CAPTULO 2

PROGRAMACIN CONCURRENTE:
THREADS
2.1 INTRODUCCIN
Todos los programas Java que hemos visto hasta ahora se ejecutan de
manera independiente a otros programas Java que podamos tener en nuestro sistema.
Si quisiramos, por ejemplo, desarrollar una aplicacin Telefono, tendramos que
programar estas dos actividades:
Recoger sonidos con un micrfono y enviarlos en tiempo real a otro
ordenador.
Recibir los sonidos que nos llegan desde otro ordenador y reproducirlos por
los altavoces.
Si queremos poder hablar y escuchar lo que nos dicen, de manera
simultnea, utilizando los conocimientos adquiridos hasta el momento solo tenemos
una opcin: abrir dos consolas en nuestro sistema y ejecutar cada aplicacin (la que
enva sonido y la que recibe sonido) en cada consola.
La solucin adoptada aprovecha la capacidad que tienen los sistemas
operativos para ejecutar varios procesos de manera simultnea (paralela,
concurrente); en este caso, el sistema operativo ejecuta en paralelo cada una de
nuestras mquinas virtuales Java (JVM), que se encuentran en las dos consolas
abiertas.
Si quisiramos darle un uso profesional a nuestra aplicacin, enseguida
descubriramos que no es factible vender una solucin que requiere ejecutar
distintas partes del programa por separado. Lo adecuado es que una misma
aplicacin Java pueda ejecutar varios procesos concurrentemente.
Los Threads (hilos) de Java permiten ejecutar en paralelo varios programas
que se encuentran en la misma aplicacin. En el ejemplo Telefono, haciendo uso de
threads, podemos ejecutar simultneamente el programa que captura y enva sonidos

14 JESS BOBADILLA SANCHO

con el programa que los recibe y los manda a los altavoces; de esta manera,
podemos ejecutar toda la funcionalidad desde una sola consola.

2.2 DEFINICIN DE PROGRAMAS CONCURRENTES


Existen dos formas de definir una clase para que pueda ejecutarse en
paralelo a otras clases:
Extendiendo la clase Thread
Implementando el interfaz Runnable
Ejemplos:
public class SeEjecutaConcurrentemente extends Thread
public class SeEjecutaConcurrentemente implements Runnable
Puesto que Java no soporta herencia mltiple, si necesitamos heredar los
miembros de una clase resulta necesario hacer uso del interfaz Runnable; por
ejemplo, si deseamos crear un applet que se ejecute concurrentemente con otros
programas, podemos definir nuestra clase como:
public class AppletConcurrente extends java.applet.Applet implements Runnable
El interfaz Runnable es extremadamente sencillo: nicamente contiene el
mtodo run(). Cuando un objeto que imple menta este interfaz se usa para crear un
thread, al arrancar el thread se ejecuta automticamente el mtodo run.
La clase Thread implementa el interfaz Runnable y contiene un variado
grupo de constructores y mtodos que permiten definir el comportamiento y
evolucin de los programas concurrentes.
Las estructuras ms simples de programas que usan threads son:
Empleando la clase Tread:
1
2
3
4
5
6

class TelefonoEnvia extends Thread {


.... // propiedades, constructores y mtodos de la clase
public void run() {
// recoge sonidos del microfono y los enva por la
//red
}
}

JESS BOBADILLA SANCHO

15

Para crear y arrancar un thread con el comportamiento de TelefonoEnvia :


1
2

TelefonoEnvia InstanciaEnvia = new TelefonoEnvia();


InstanciaEnvia.start();

Empleando el interfaz Runnable :


1
2
3
4
5
6
7

class TelefonoEnvia implements Runnable {


.... // propiedades, constructores y mtodos de la
.... // clase
public void run() {
// recoge sonidos del microfono y los enva por la red
}
}

1
2

TelefonoEnvia InstanciaEnvia = new TelefonoEnvia();


new Thread(InstanciaEnvia).start();

Para crear y arrancar un thread con el comportamiento de TelefonoEnvia :

Como se puede apreciar en las estructuras de programa mostradas, para


arrancar un thread debemos utilizar el mtodo start, que a su vez provoca la
ejecucin de l mtodo run. En la ltima lnea de cdigo mostrada, se utiliza un
constructor de la clase Thread que admite un objeto Runnable como parmetro.
Un mtodo importante de la clase Thread es:
static void sleep (long milisegundos) // detiene la ejecucin del thread al
// menos el nmero de milisegundos indicado

2.3 PRIMER EJEMPLO


Con los conceptos explicados hasta el momento estamos en condiciones de
afrontar nuestro primer ejemplo, que hace uso de dos threads: cada thread imprime
una frase en momentos diferentes.
La clase ThreadBasico (lnea 3) implementa el interfaz Runnable, y por
tanto su nico mtodo run (lnea 13). Cada instancia de la clase ThreadBasico
incorpora las propiedades Frase y Aleatorio, que contendrn el String a imprimir y
una medida del tiempo que se tardar en hacerlo.

16 JESS BOBADILLA SANCHO

El String a imprimir le llega a la clase a travs de su constructor (lnea 8). La


propiedad Aleatorio contiene el valor numrico aleatorio que le proporciona la clase
Random (lnea 10).
El mtodo run (que se invoca automticamente tras el mtodo start)
imprime la frase por consola (lnea 16) y se duerme durante un tiempo aleatorio
(lnea 17). Estas acciones se repiten indefinidamente en un bucle (lneas 15 y 19). El
bloque try-catch resulta necesario para contemplar el caso de que nuestro thread
sea interrumpido.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

import java.util.Random;
public class ThreadBasico implements Runnable {
private String Frase;
private Random Aleatorio;
public ThreadBasico (String Frase) {
this.Frase = Frase;
Aleatorio = new Random();
} // Constructor
public void run() {
try {
do {
System.out.println (Frase);
Thread.sleep( (long) (Math.abs(Aleatorio.nextInt())
% 500));
} while (true);
} catch (InterruptedException e) {}
} // run
}

// class

Para probar el comportamiento de la clase ThreadBasico se proporciona la


clase ThreadBasicoMain, donde se crean dos instancias de ThreadBasico (lneas 4 a
7). Cada instancia recibe una palabra de la consola a travs del parmetro de tipo
String[] del mtodo main; de esta manera, tecleando en consola el comando de
ejecucin: java ThreadBasicoMain uno dos, en args[0] recogemos el valor uno y
en args[1] el valor dos.
En las lneas 10 y 11 se arrancan los dos threads instanciados, lo que
provoca la ejecucin del mtodo run de ambas instancias. El resultado de una
ejecucin concreta se muestra a continuacin del cdigo de la clase.
1
2

public class ThreadBasicoMain {

JESS BOBADILLA SANCHO

17

3 public static void main(String[] args) {


4
Thread PrimerHilo = new Thread
5
(new ThreadBasico (args[0]));
6
Thread SegundoHilo = new Thread
7
(new ThreadBasico (args[1]));
8
9
10
PrimerHilo.start();
11
SegundoHilo.start();
12
13 }
14 }

2.4 EJEMPLO CON UN NMERO VARIABLE DE HILOS


(THREADS)
El ejemplo que se desarrolla en este apartado es bastante similar al anterior,
aunque en este caso el nmero de hilos que creamos vara dependiendo de los datos
de entrada.
La aplicacin recoge una palabra que se le pasa como argumento y escribe
cada una de sus letras en un orden aleatorio; para conseguir este efecto se asigna un
hilo a cada letra (o carcter), se detiene cada hilo durante un tiempo aleatorio y
posteriormente se impr ime el carcter. La estructura de la aplicacin presenta las
siguientes dependencias:
PruebaLetrasHilos

LetrasHilos

CHilo

18 JESS BOBADILLA SANCHO

Chilo implementa el interfaz Runnable . En su constructor (lnea 6) recoge


un String de tamao uno. Cuando se activa el hilo (thread) en primer lugar se le
duerme durante un tiempo aleatorio (lneas 12 y 13) y posteriormente se imprime
el carcter (lnea 14).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

import java.util.Random;
public class CHilo implements Runnable {
private String Caracter;
public CHilo (String Caracter) {
this.Caracter = Caracter;
}
public void run() {
try {
Thread.sleep( (long)
(Math.abs(new Random().nextInt())%1000));
System.out.print(Caracter);
} catch (InterruptedException e) {}
}
}

La clase LetrasHilos define un array de threads (lnea 4) y posteriormente


itera en un bucle tantas veces como posiciones tiene el String que recoge como
parmetro (lnea 5). En cada iteracin se crea un thread utilizando la clase CHilo y
se le pasa como argumento un carcter del String (lneas 6 y 7). En la lnea 8 se
arranca el hilo.
Aunque el array de hilos no es necesario en el ejemplo, resulta adecuado
mostrar la manera de crear estas estructuras de hilos, puesto que en otras ocasiones
son muy tiles.
1
2
3
4
5
6
7
8
9
10
11
12

public class LetrasHilos {


public LetrasHilos (String Frase) {
Thread[] Hilo = new Thread[Frase.length()];
for (int i=0; i!=Frase.length();i++) {
Hilo[i] = new Thread
(new CHilo(Frase.substring(i,i+1)));
Hilo[i].start();
}
return;
}
}

JESS BOBADILLA SANCHO

19

El ejemplo se completa proporcionando una clase que contenga el mtodo


main e instancie a la clase LetrasHilos, pasando un String como argumento. Esto se
realiza en la lnea 8 de la clase PruebaLetrasHilos.
1
2
3
4
5
6
7
8
9
10
11

public class PruebaLetrasHilos {


public static void main(String[] args) {
if (args.length!=1) {
System.out.println("Hay que introducir un argumento");
System.exit(0);
}
LetrasHilos Instancia = new LetrasHilos(args[0]);
}
}

En el siguiente grfico se muestra la consola del sistema con varias


ejecuciones de la clase PruebaLetrasHilos; en cada una de ellas el orden de las
letras es diferente, como cabe esperar por los tiempos aleatorios en los que se
despiertan las distintas instancias de la clase CHilo.

2.5 EXCLUSIN MUTUA (MODIFICADOR


SYNCHRONIZED)
Cuando se programa haciendo uso de concurrencia (paralelismo) hay que
tener en cuenta la necesidad de establecer, en ocasiones, zonas de exclusin en el
acceso a los recursos. Pongamos un ejemplo de esta situacin: para controlar el paso
a un tnel de un solo carril, en ambos lados del tnel se colocan semforos. Cuando
un automvil encuentra el semforo en verde, se le da permiso de entrada e
inmediatamente se pone el semforo en rojo, hasta que sale del tnel. El cdigo
quedara como:
1
2
3

.....
if (Semaforo.equals(Verde)) {
PermisoPaso();

20 JESS BOBADILLA SANCHO

4
5
6

Semaforo=Rojo
}
.......................

Si dos o ms threads (que se ejecutan en paralelo) leen simultneamente el


valor de la propiedad Semaforo y determinan que est en verde, esos threads
ejecutarn al mismo tiempo el mtodo PermisoPaso, produciendo una situacin
errnea (y en este caso muy peligrosa).
Para evitar situaciones como la ilustrada podemos proteger el acceso a los
recursos (en nuestro ejemplo el recurso abstracto es el tnel y el recurso concreto en
la variable Semaforo). Java permite definir mtodos de exclusin mutua, donde
slo puede ejecutarse un hilo en cada momento.
Colocando el modificador synchronized en un mtodo conseguimos que su
ejecucin sea exclusiva, es decir, que no podr haber dos o ms hilos ejecutando
simultneamente ese mtodo.
El mtodo PeticionEntradaATunel, al incluir el modificador synchronized,
resuelve el problema de exclusin mutua que hemos planteado.
1
2
3
4
5
6
7
8

public synchronized boolean PeticionEntradaATunel(){


.....
if (Semaforo.equals(Verde)) {
PermisoPaso();
Semaforo=Rojo
}
.......................
}

2.6 MTODOS MS IMPORTANTES DE LA CLASE


THREAD
Adems de los dos constructores ms utilizados de esta clase:
Thread() y Thread(Runnable destino)
existe una amplia coleccin de mtodos destinados, en su mayora, a
controlar la ejecucin de los hilos. La siguiente tabla muestra los mtodos ms tiles
y comnmente utilizados:

JESS BOBADILLA SANCHO

Mtodo
void start()
void run()

static void sleep(long ms)


void destroy()
void setPriority(int Prioridad)
int getPriority()
final void join()
static Thread currentThread()
boolean isAlive()
void setDaemon(boolean on)

public final bolean isDaemon()


void setName(String name)
String getName()

21

Accin
Provoca el comienzo de la ejecucin del hilo.
Se ejecuta automticamente tras start, cuando el hilo se ha
construido a partir del interfaz Runnable (o la clase
Thread).
Detiene la ejecucin del hilo durante, al menos, los
milisegundos indicados
Elimina el hilo sin liberara recursos
Establece una prioridad para el hilo (MAX_PRIORITY,
MIN_PRIORITY, NORM_PRIORITY)
Indica la prioridad del hilo
Espera a que este hilo termine
Devuelve un apuntador al hilo que se est ejecutando
Indica si el hilo ha sido arrancado y todava no ha
terminado
Establece el hilo como demonio o como usuario. Los hilos
demonio estn supeditados a los hilos que los han creado,
de tal manera que cuando el creador termina, sus hijos
demonio tambin finalizan
Indica si el hilo es de tipo demonio o usuario
Asigna un nombre al hilo
Devuelve el nombre del hilo

Vous aimerez peut-être aussi