15.05.2013 Views

Clase Thread - docencia de la ETSIT-URJC

Clase Thread - docencia de la ETSIT-URJC

Clase Thread - docencia de la ETSIT-URJC

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

Tema 14: Concurrencia<br />

Introducción a Java<br />

GSyC, 2007


Introducción<br />

Las aplicaciones normalmente están compuestas <strong>de</strong> un<br />

único flujo <strong>de</strong> ejecución que ejecuta todas <strong>la</strong>s<br />

instrucciones <strong>de</strong>l programa<br />

Java proporciona soporte para <strong>la</strong> programación <strong>de</strong><br />

aplicaciones concurrentes: varios flujos <strong>de</strong> ejecución<br />

simultáneos en el mismo programa<br />

Un <strong>Thread</strong> es un flujo/hilo <strong>de</strong> ejecución, (tarea en<br />

Ada). Es una CPU virtual.<br />

En Java se pue<strong>de</strong>n crear múltiples threads, a<strong>de</strong>más<br />

<strong>de</strong>l flujo principal que da comienzo al programa,<br />

ejecutándose todos concurrentemente<br />

2


Introducción<br />

Un thread está compuesto por:<br />

• Código que ejecuta el thread<br />

• Datos que consulta/modifica el thread<br />

• Prioridad <strong>de</strong>l thread: utilizada para que el p<strong>la</strong>nificador <strong>de</strong>cida qué thread ejecutar<br />

cuando hay varios posibles<br />

Cómo se implementan los threads<br />

• Cuando se interrumpe <strong>la</strong> ejecución <strong>de</strong> un thread se salva el contador <strong>de</strong> programa, los<br />

registros y su pi<strong>la</strong> para po<strong>de</strong>r recuperar su estado cuando se continúe su ejecución<br />

• Pue<strong>de</strong> haber un thread por procesador en máquinas multiprocesadoras, o un thread<br />

por cada proceso <strong>de</strong>l sistema operativo (SO), o un thread por cada “proceso ligero”<br />

<strong>de</strong>l SO, o múltiples threads por cada proceso <strong>de</strong>l SO, contro<strong>la</strong>dos por un p<strong>la</strong>nificador<br />

que corre en espacio <strong>de</strong> usuario<br />

El soporte para threads lo pue<strong>de</strong> proporcionar el propio lenguaje, o una biblioteca aparte


Introducción<br />

Aspectos a tener en cuenta al añadir threads a un<br />

lenguaje <strong>de</strong> programación<br />

• Políticas <strong>de</strong> p<strong>la</strong>nificación <strong>de</strong> los threads<br />

• Cómo mo<strong>de</strong><strong>la</strong>r <strong>la</strong> periodicidad<br />

• Cómo implementar los threads: estructuras <strong>de</strong> control<br />

nuevas, o módulos especiales, o métodos especiales en<br />

módulos <strong>de</strong> <strong>la</strong> biblioteca<br />

• Cómo expresar el procesamiento que se llevará a cabo<br />

• Cómo expresar <strong>la</strong> semántica <strong>de</strong>l ciclo <strong>de</strong> vida <strong>de</strong> un thread:<br />

creación, arranque, parada<br />

• Cómo mo<strong>de</strong><strong>la</strong>r <strong>la</strong> sincronización y comunicación entre threads<br />

Cómo evitar condiciones <strong>de</strong> carrera: problemas que surgen al<br />

compartir estructuras <strong>de</strong> datos entre threads


<strong>Thread</strong>s en Java<br />

P<strong>la</strong>nificación <strong>de</strong> threads<br />

• Cada thread tiene su prioridad<br />

• Si hay más threads que procesadores en el or<strong>de</strong>nador, se elige el<br />

thread que se ejecutará según su prioridad<br />

2 posibilida<strong>de</strong>s, <strong>de</strong>pendientes <strong>de</strong> <strong>la</strong> implementación:<br />

Política expulsiva: cada cierto tiempo se le quita el procesador al<br />

thread que lo tiene<br />

Política no expulsiva: hasta que no se bloquea un thread no se le<br />

quita el procesador<br />

Ejecución periódica <strong>de</strong> threads<br />

• El método sleep (n) suspen<strong>de</strong> <strong>la</strong> ejecución <strong>de</strong>l thread durante al<br />

menos n milisegundos


<strong>Thread</strong>s en Java<br />

Java integra los threads con <strong>la</strong> orientación a objetos<br />

• Un thread es un objeto cuya c<strong>la</strong>se hereda <strong>de</strong> java.<strong>la</strong>ng.<strong>Thread</strong><br />

• El código que ejecutará el thread se escribe en su método<br />

run().<br />

• ¡El método run() NO se <strong>de</strong>be, aunque se pue<strong>de</strong>, invocar<br />

directamente!<br />

Ciclo <strong>de</strong> vida <strong>de</strong>l thread<br />

• Creación: Un thread es un objeto: se crea mediante su constructor<br />

• Arranque: El programador invoca el método start() <strong>de</strong>l thread<br />

para iniciar su ejecución. Es este método el que invocará el método<br />

run()<br />

• Terminación: Un thread termina su ejecución cuando su método<br />

run() ejecuta <strong>la</strong> sentencia return


Definición <strong>de</strong> threads<br />

En Java se pue<strong>de</strong> <strong>de</strong>finir y crear un<br />

thread <strong>de</strong> 2 formas:<br />

• Extendiendo <strong>la</strong> c<strong>la</strong>se <strong>Thread</strong><br />

• Se <strong>de</strong>c<strong>la</strong>ra una subc<strong>la</strong>se <strong>de</strong> <strong>Thread</strong> y se<br />

reemp<strong>la</strong>za su método run()<br />

• Luego se crea una instancia <strong>de</strong> <strong>la</strong> subc<strong>la</strong>se<br />

Implementando <strong>la</strong> interfaz Runnable<br />

• Se <strong>de</strong>c<strong>la</strong>ra una c<strong>la</strong>se que implementa <strong>la</strong><br />

interfaz Runnable, <strong>de</strong>finiendo el método<br />

run()<br />

• Luego se crea una instancia <strong>de</strong> esta c<strong>la</strong>se y se<br />

le pasa al constructor <strong>Thread</strong>()


Extendiendo <strong>la</strong> c<strong>la</strong>se <strong>Thread</strong><br />

public c<strong>la</strong>ss Nombre extends <strong>Thread</strong> {<br />

public Nombre ( String nombre ){<br />

super( nombre );<br />

}<br />

public void run() {<br />

while( true ) {<br />

System.out.println<br />

(System.currentTimeMillis() + ": " + getName());<br />

}<br />

}<br />

}<br />

public c<strong>la</strong>ss Prueba {<br />

public static void main( String[] args ) {<br />

Nombre n1 = new Nombre ( "Jaime" );<br />

Nombre n2 = new Nombre ( " Lo<strong>la</strong>" );<br />

n1.start();<br />

n2.start();<br />

}<br />

}<br />

<strong>Thread</strong> principal<br />

<strong>Thread</strong> Jaime<br />

<strong>Thread</strong> Lo<strong>la</strong><br />

$ java Prueba<br />

1177437609460: Jaime<br />

1177437609460: Lo<strong>la</strong><br />

1177437609461: Jaime<br />

1177437609461: Lo<strong>la</strong><br />

1177437609461: Jaime<br />

1177437609461: Lo<strong>la</strong><br />

1177437609461: Jaime<br />

1177437609461: Jaime<br />

1177437609461: Jaime<br />

1177437609461: Jaime<br />

1177437609461: Jaime<br />

1177437609461: Jaime<br />

1177437609461: Jaime<br />

1177437609461: Jaime<br />

1177437609461: Jaime<br />

1177437609461: Jaime<br />

1177437609461: Jaime<br />

1177437609461: Jaime<br />

1177437609461: Lo<strong>la</strong><br />

1177437609461: Jaime


Cuidado con start() y run()!<br />

public c<strong>la</strong>ss Prueba {<br />

public static void main( String[] args ) {<br />

Nombre n1 = new Nombre ( "Jaime" );<br />

Nombre n2 = new Nombre ( " Lo<strong>la</strong>" );<br />

n1.run();<br />

n2.run();<br />

}<br />

}<br />

public c<strong>la</strong>ss Prueba {<br />

public static void main( String[] args ) {<br />

Nombre n1 = new Nombre ( "Jaime" );<br />

Nombre n2 = new Nombre ( " Lo<strong>la</strong>" );<br />

n1.start();<br />

n2.start();<br />

}<br />

}


Estados <strong>de</strong>l thread<br />

Cuando se crea un thread, éste no tiene aún <strong>la</strong> capacidad <strong>de</strong><br />

ejecución.<br />

Cuando se invoca al método start() el thread se encuentra en estado<br />

<strong>de</strong> “ejecutable” (“runnable”). Eso no significa que se ejecute!!!<br />

Cuando el p<strong>la</strong>nificador lo <strong>de</strong>cida, el thread pasa a un estado <strong>de</strong><br />

“ejecutando” (“running”).<br />

El thread pue<strong>de</strong> pasar a otro estado intermedio l<strong>la</strong>mado “bloqueado”<br />

(“blocked”) si realiza una operación <strong>de</strong> bloqueo (p.e. entrada/salida)<br />

Cuando sale <strong>de</strong>l estado <strong>de</strong> bloqueo, pasa <strong>de</strong> nuevo al estado <strong>de</strong><br />

“ejecutable”


Implementando <strong>la</strong> interfaz Runnable<br />

public c<strong>la</strong>ss Nombre implements Runnable {<br />

String nombre;<br />

public Nombre ( String nombre ){<br />

this.nombre = nombre;<br />

}<br />

public void run() {<br />

while( true ) {<br />

System.out.println<br />

(System.currentTimeMillis() + ": " + nombre);<br />

}<br />

}<br />

}<br />

public c<strong>la</strong>ss Prueba {<br />

public static void main( String[] args ) {<br />

Runnable n1 = new Nombre ( "Jaime" );<br />

Runnable n2 = new Nombre ( " Lo<strong>la</strong>" );<br />

<strong>Thread</strong> t1 = new <strong>Thread</strong>(n1); t1.start();<br />

<strong>Thread</strong> t2 = new <strong>Thread</strong>(n2); t2.start();<br />

}<br />

}<br />

<strong>Thread</strong> principal<br />

<strong>Thread</strong> Jaime<br />

<strong>Thread</strong> Lo<strong>la</strong><br />

$ java Prueba<br />

1177438860272: Lo<strong>la</strong><br />

1177438860272: Lo<strong>la</strong><br />

1177438860272: Jaime<br />

1177438860272: Lo<strong>la</strong><br />

1177438860272: Jaime<br />

1177438860272: Lo<strong>la</strong><br />

1177438860272: Jaime<br />

1177438860272: Lo<strong>la</strong><br />

1177438860272: Jaime<br />

1177438860272: Lo<strong>la</strong><br />

1177438860272: Jaime<br />

1177438860272: Jaime<br />

1177438860272: Jaime<br />

1177438860272: Jaime<br />

1177438860272: Jaime<br />

1177438860272: Jaime<br />

1177438860272: Lo<strong>la</strong><br />

1177438860272: Jaime<br />

1177438860272: Lo<strong>la</strong><br />

1177438860272: Jaime<br />

1177438860272: Lo<strong>la</strong><br />

1177438860272: Jaime


Implementando <strong>la</strong> interfaz Runnable<br />

¿Cuándo implementar <strong>la</strong> interfaz Runnable en lugar<br />

<strong>de</strong> exten<strong>de</strong>r <strong>la</strong> c<strong>la</strong>se <strong>Thread</strong>?<br />

• Cuando una c<strong>la</strong>se hereda <strong>de</strong> otra: no podría heredar también<br />

<strong>de</strong> <strong>Thread</strong><br />

• Cuando no queremos heredar todos los métodos <strong>de</strong> <strong>la</strong> c<strong>la</strong>se<br />

<strong>Thread</strong><br />

• Cuando queremos diseñar el programa sin tener en cuenta <strong>la</strong><br />

concurrencia, y posteriormente queremos añadir<br />

concurrencia<br />

A pesar <strong>de</strong> no heredar <strong>de</strong> <strong>Thread</strong> po<strong>de</strong>mos invocar<br />

métodos <strong>de</strong> instancia <strong>de</strong> <strong>la</strong> c<strong>la</strong>se <strong>Thread</strong>:<br />

• <strong>Thread</strong>.current<strong>Thread</strong>() <strong>de</strong>vuelve el thread actual<br />

Ej. <strong>Thread</strong>.current<strong>Thread</strong>().getName()


<strong>Thread</strong>.sleep()<br />

El método <strong>Thread</strong>.sleep() es un método estático<br />

<strong>de</strong> <strong>la</strong> c<strong>la</strong>se <strong>Thread</strong>: suspen<strong>de</strong> <strong>la</strong> ejecución <strong>de</strong>l thread<br />

que lo ejecuta durante el número <strong>de</strong> milisegundos<br />

especificado<br />

<strong>Thread</strong>.sleep () tiene una cláusu<strong>la</strong> throws<br />

InterruptedException, pero run() no, por lo que<br />

hay que tratar <strong>la</strong> excepción<br />

La ejecución <strong>de</strong>l bucle while no es muy precisa en<br />

cuanto al periodo


<strong>Thread</strong>.sleep()<br />

public c<strong>la</strong>ss Nombre extends <strong>Thread</strong> {<br />

int periodo;<br />

public Nombre ( String nombre, int periodo ){<br />

super( nombre );<br />

this.periodo = periodo;<br />

}<br />

public void run() {<br />

while( true ) {<br />

System.out.println<br />

(System.currentTimeMillis() + ": " + getName());<br />

try { <strong>Thread</strong>.sleep ( periodo ); }<br />

catch (InterruptedException e) {return ;}<br />

}<br />

}<br />

}<br />

public c<strong>la</strong>ss Prueba {<br />

public static void main( String[] args ) {<br />

Nombre n1 = new Nombre ( "Jaime”, 500 );<br />

Nombre n2 = new Nombre ( " Lo<strong>la</strong>”, 100 );<br />

n1.start();<br />

n2.start();<br />

}<br />

}<br />

<strong>Thread</strong> principal<br />

<strong>Thread</strong> Jaime<br />

<strong>Thread</strong> Lo<strong>la</strong><br />

$ java Prueba<br />

1177448963165: Jaime<br />

1177448963165: Lo<strong>la</strong><br />

1177448963265: Lo<strong>la</strong><br />

1177448963366: Lo<strong>la</strong><br />

1177448963466: Lo<strong>la</strong><br />

1177448963566: Lo<strong>la</strong><br />

1177448963665: Jaime<br />

1177448963667: Lo<strong>la</strong><br />

1177448963767: Lo<strong>la</strong><br />

1177448963867: Lo<strong>la</strong><br />

1177448963967: Lo<strong>la</strong><br />

1177448964068: Lo<strong>la</strong><br />

1177448964166: Jaime<br />

1177448964168: Lo<strong>la</strong><br />

1177448964268: Lo<strong>la</strong><br />

1177448964369: Lo<strong>la</strong><br />

1177448964469: Lo<strong>la</strong><br />

1177448964569: Lo<strong>la</strong>


Condiciones <strong>de</strong> carrera<br />

El siguiente programa tiene condiciones <strong>de</strong> carrera<br />

que no siempre se manifiestan cuando se ejecuta<br />

Los 2 threads que crea el programa principal<br />

comparten <strong>la</strong> misma instancia <strong>de</strong> <strong>la</strong> c<strong>la</strong>se Hucha<br />

El comportamiento <strong>de</strong>seable es que todas <strong>la</strong>s veces<br />

que se l<strong>la</strong>me al método mete() que<strong>de</strong>n reflejadas en<br />

el estado <strong>de</strong> <strong>la</strong> variable ahorros <strong>de</strong> <strong>la</strong> hucha<br />

• Sin embargo no siempre se obtiene este resultado, como se<br />

ve en <strong>la</strong>s ejecuciones <strong>de</strong>l programa


Ejemplo simple<br />

public c<strong>la</strong>ss Pi<strong>la</strong> {<br />

}<br />

int idx = 0;<br />

char [] data = new char[6];<br />

public void poner(char c) {<br />

}<br />

data[idx] = c;<br />

idx++;<br />

public char quitar() {<br />

}<br />

idx--;<br />

return data[idx];


Ejemplo<br />

El problema con el ejemplo anterior se reproduce<br />

cuando dos o más hilos acce<strong>de</strong>n a los métodos poner<br />

y quitar <strong>de</strong> forma <strong>de</strong>scontro<strong>la</strong>da.<br />

Debemos evitar que mientras un hilo intenta poner<br />

(quitar) el otro realice una operación que altere los<br />

datos.<br />

public c<strong>la</strong>ss Pi<strong>la</strong> {<br />

...<br />

...<br />

}<br />

public void poner(char c) {<br />

}<br />

synchronized (this) {<br />

data[idx] = c;<br />

idx++;<br />

}


public c<strong>la</strong>ss Hucha {<br />

private int ahorros = 0;<br />

public void mete ( int cantidad ) {<br />

ahorros = ahorros + cantidad;<br />

}<br />

public int ahorros () { return ahorros; }<br />

}<br />

public c<strong>la</strong>ss Ahorrador extends <strong>Thread</strong> {<br />

Hucha hucha;<br />

int iteraciones;<br />

public Ahorrador ( String nombre, Hucha hucha, int iteraciones ) {<br />

super (nombre);<br />

this.hucha = hucha;<br />

this.iteraciones = iteraciones;<br />

}<br />

public void run () {<br />

for (int i=1; i


$ java PruebaAhorradores 10<br />

Ahorros tras Pedro: 10<br />

Ahorros tras Juan : 20<br />

$ java PruebaAhorradores 100<br />

Ahorros tras Pedro: 100<br />

Ahorros tras Juan : 200<br />

$ java PruebaAhorradores 1000<br />

Ahorros tras Pedro: 1000<br />

Ahorros tras Juan : 2000<br />

$ java PruebaAhorradores 1000<br />

Ahorros tras Pedro: 1497<br />

Ahorros tras Juan : 1995<br />

$ java PruebaAhorradores 100000<br />

Ahorros tras Pedro: 100347<br />

Ahorros tras Juan : 184980<br />

$ java PruebaAhorradores 100000<br />

Ahorros tras Juan : 86727<br />

Ahorros tras Pedro: 171360<br />

$ java PruebaAhorradores 100000<br />

Ahorros tras Juan : 104166<br />

Ahorros tras Pedro: 188799<br />

Parece que funciona pero…<br />

Parece que funciona pero…<br />

Parece que funciona pero…<br />

… NO funciona: hay condiciones <strong>de</strong> carrera<br />

… NO funciona: hay condiciones <strong>de</strong> carrera<br />

… NO funciona: hay condiciones <strong>de</strong> carrera<br />

… NO funciona : hay condiciones <strong>de</strong> carrera


Condiciones <strong>de</strong> carrera<br />

¡ La sentencia <strong>de</strong> asignación NO se ejecuta <strong>de</strong> manera atómica !<br />

public c<strong>la</strong>ss Hucha {<br />

private int ahorros = 0;<br />

public void mete ( int cantidad ) {<br />

ahorros = ahorros + cantidad;<br />

}<br />

public int ahorros () { return ahorros; }<br />

}<br />

13 MOVE ahorros, A<br />

14 ADD A, cantidad<br />

15 MOVE A, ahorros<br />

<strong>Thread</strong> Pedro<br />

<strong>Thread</strong> Juan<br />

A cantidad PC ahorros<br />

0 1 13 0<br />

A cantidad PC ahorros<br />

0 1 13 0<br />

A cantidad PC ahorros<br />

1 1 14 0<br />

A cantidad PC ahorros<br />

1 1 15 1<br />

A cantidad PC ahorros<br />

0 1 13 1<br />

A cantidad PC ahorros<br />

1 1 14 1<br />

A cantidad PC ahorros<br />

1 1 15 1


Sincronización y comunicación <strong>de</strong> threads<br />

Los threads en Java se comunican y sincronizan l<strong>la</strong>mando a métodos<br />

marcados como synchronized, pertenecientes a otros objetos<br />

Un objeto con uno o más métodos synchronized tiene un lock<br />

interno (es un mutex, y sólo hay uno por objeto)<br />

• Si un thread l<strong>la</strong>ma a un método synchronized <strong>de</strong> un objeto que no<br />

está bloqueado, pue<strong>de</strong> continuar, bloqueándose atómicamente el objeto<br />

mientras dura <strong>la</strong> ejecución <strong>de</strong>l método synchronized<br />

• Si un thread l<strong>la</strong>ma a un método synchronized <strong>de</strong> un objeto<br />

bloqueado por otro thread, se suspen<strong>de</strong> <strong>la</strong> ejecución <strong>de</strong>l thread<br />

l<strong>la</strong>mante hasta que el objeto se <strong>de</strong>sbloquee


public c<strong>la</strong>ss Hucha {<br />

private int ahorros = 0;<br />

public synchronized void mete ( int cantidad ) {<br />

ahorros = ahorros + cantidad;<br />

}<br />

public synchronized int ahorros () { return ahorros; }<br />

}<br />

public c<strong>la</strong>ss Ahorrador extends <strong>Thread</strong> {<br />

Hucha hucha;<br />

int iteraciones;<br />

public Ahorrador ( String nombre, Hucha hucha, int iteraciones ) {<br />

super (nombre);<br />

this.hucha = hucha;<br />

this.iteraciones = iteraciones;<br />

}<br />

public void run () {<br />

for (int i=1; i


$ java PruebaAhorradores 10<br />

Ahorros tras Pedro: 10<br />

Ahorros tras Juan : 20<br />

$ java PruebaAhorradores 100<br />

Ahorros tras Pedro: 100<br />

Ahorros tras Juan : 200<br />

$ java PruebaAhorradores 1000<br />

Ahorros tras Pedro: 1292<br />

Ahorros tras Juan : 2000<br />

$ java PruebaAhorradores 1000<br />

Ahorros tras Pedro: 1499<br />

Ahorros tras Juan : 2000<br />

$ java PruebaAhorradores 100000<br />

Ahorros tras Pedro: 194544<br />

Ahorros tras Juan : 200000<br />

$ java PruebaAhorradores 100000<br />

Ahorros tras Juan : 191417<br />

Ahorros tras Pedro: 200000<br />

$ java PruebaAhorradores 100000<br />

Ahorros tras Juan : 197544<br />

Ahorros tras Pedro: 200000


Sincronización y comunicación <strong>de</strong> threads<br />

Mediante l<strong>la</strong>madas a wait(), notify() y notifyAll()<br />

<strong>de</strong>s<strong>de</strong> <strong>de</strong>ntro <strong>de</strong> métodos synchronized se pue<strong>de</strong> suspen<strong>de</strong>r o<br />

<strong>de</strong>suspen<strong>de</strong>r <strong>la</strong> ejecución <strong>de</strong> métodos en función <strong>de</strong>l estado <strong>de</strong>l<br />

objeto


public c<strong>la</strong>ss Hucha {<br />

private int ahorros = 0; private final int MAXIMO = 10;<br />

public synchronized void mete (int cantidad) {<br />

while (ahorros + cantidad > MAXIMO)<br />

try {wait();} catch (InterruptedException e) {return;};;<br />

ahorros = ahorros + cantidad;<br />

notifyAll(); // Despertamos a los gastadores, y al resto<br />

}<br />

public synchronized void saca (int cantidad) {<br />

while (ahorros < cantidad)<br />

try {wait();} catch (InterruptedException e) {return;};<br />

ahorros = ahorros - cantidad;<br />

notifyAll(); // Despertamos a los ahorradores, y al resto<br />

}<br />

public synchronized int ahorros () { return ahorros; }<br />

}<br />

public c<strong>la</strong>ss Gastador extends <strong>Thread</strong> {<br />

Hucha hucha; int iteraciones;<br />

public Gastador<br />

( String nombre, Hucha hucha, int iteraciones ) {<br />

super (nombre);<br />

this.hucha = hucha;<br />

this.iteraciones = iteraciones;<br />

}<br />

public void run () {<br />

for (int i=1; i


$ java PruebaAhorradores 1000 1000 2000<br />

Ahorros tras ahorrador 1: 7<br />

Ahorros tras ahorrador 2: 6<br />

Ahorros tras gastador 1 : 0<br />

$ java PruebaAhorradores 5 5 10<br />

Ahorros tras ahorrador 1: 5<br />

Ahorros tras gastador 1 : 0<br />

Ahorros tras ahorrador 2: 10<br />

$ java PruebaAhorradores 100 100 200<br />

Ahorros tras ahorrador 2: 0<br />

Ahorros tras gastador 1 : 0<br />

Ahorros tras ahorrador 1: 0<br />

$ java PruebaAhorradores 100 100 500<br />

Ahorros tras ahorrador 1: 4<br />

Ahorros tras ahorrador 2: 7<br />

^C<br />

$ java PruebaAhorradores 50 50 90<br />

Ahorros tras ahorrador 1: 5<br />

Ahorros tras gastador 1 : 1<br />

Ahorros tras ahorrador 2: 10<br />

$ java PruebaAhorradores 50 50 70<br />

Ahorros tras ahorrador 1: 10<br />

Ahorros tras gastador 1 : 10<br />

^C<br />

26


<strong>C<strong>la</strong>se</strong>s e interfaces en java.<strong>la</strong>ng<br />

Interfaz Runnable<br />

public interface Runnable {<br />

void run();<br />

}<br />

Métodos re<strong>la</strong>cionados con threads<br />

<strong>de</strong> <strong>la</strong> c<strong>la</strong>se Object<br />

public c<strong>la</strong>ss Object {<br />

public final void wait() throws InterruptedException;<br />

public final native void wait(long timeout)<br />

throws InterruptedException;<br />

public final void wait(long timeout, int nanos)<br />

throws InterruptedException;<br />

public final native void notify();<br />

public final native void notifyAll();<br />

}<br />

<strong>C<strong>la</strong>se</strong> <strong>Thread</strong><br />

public c<strong>la</strong>ss <strong>Thread</strong> implements Runnable {<br />

public final static int MIN_PRIORITY = 1;<br />

public final static int MAX_PRIORITY = 10;<br />

public final static int NORM_PRIORITY = 5;<br />

public <strong>Thread</strong>();<br />

public <strong>Thread</strong>(String name);<br />

public <strong>Thread</strong>(Runnable runObject);<br />

public <strong>Thread</strong>(Runnable runObject, String name);<br />

public String toString();<br />

public void run();<br />

public final void start()<br />

throws Illegal<strong>Thread</strong>StateException;<br />

public final void stop() throws SecurityException;<br />

public final void suspedn() throws SecurityException;<br />

public final void resume() throws SecurityException;<br />

public final String getName();<br />

public final int getPriority();<br />

public final int setPriority(int newPriority)<br />

throws SecurityException, IllegalArgumentException;<br />

public final void join() throws InterruptedException;<br />

public final void join(long millis)<br />

throws InterruptedException;<br />

public void interrupt();<br />

public boolean isInterrupted();<br />

}<br />

public static <strong>Thread</strong> current<strong>Thread</strong>();<br />

public static void yield();<br />

public static void sleep( long millis )<br />

throws InterruptedException;<br />

public void <strong>de</strong>stroy();


Otros<br />

Yield()<br />

• Avisa al scheduler que pue<strong>de</strong> interrumpir el thread. Es útil<br />

en algunos casos, pero no suele ser fiable.<br />

// Suggesting when to switch threads with yield().<br />

public c<strong>la</strong>ss Yielding<strong>Thread</strong> extends <strong>Thread</strong> {<br />

private static Test monitor = new Test();<br />

private int countDown = 5;<br />

private static int threadCount = 0;<br />

public Yielding<strong>Thread</strong>() {<br />

super("" + ++threadCount);<br />

start();<br />

}<br />

public String toString() {<br />

return "#" + getName() + ": " + countDown;<br />

}<br />

public void run() {<br />

while(true) {<br />

System.out.println(this);<br />

if(--countDown == 0) return;<br />

yield();<br />

}<br />

}<br />

public static void main(String[] args) {<br />

for(int i = 0; i < 5; i++)<br />

new Yielding<strong>Thread</strong>();<br />

}<br />

} //


Otros<br />

Join()<br />

• Hace que el thread espere a que otro thread haya<br />

terminado.<br />

// Un<strong>de</strong>rstanding join().<br />

c<strong>la</strong>ss Sleeper extends <strong>Thread</strong> {<br />

private int duration;<br />

public Sleeper(String name, int sleepTime) {<br />

super(name);<br />

duration = sleepTime;<br />

start();<br />

}<br />

public void run() {<br />

try {<br />

sleep(duration);<br />

} catch (InterruptedException e) {<br />

System.out.println(getName() + " was interrupted. " +<br />

"isInterrupted(): " + isInterrupted());<br />

return;<br />

}<br />

System.out.println(getName() + " has awakened");<br />

}<br />

}<br />

c<strong>la</strong>ss Joiner extends <strong>Thread</strong> {<br />

private Sleeper sleeper;<br />

public Joiner(String name, Sleeper sleeper) {<br />

super(name);<br />

this.sleeper = sleeper;<br />

start();<br />

}<br />

public void run() {<br />

try {<br />

sleeper.join();<br />

} catch (InterruptedException e) {<br />

throw new RuntimeException(e);<br />

}<br />

System.out.println(getName() + " join completed");<br />

}<br />

}


Join<br />

public c<strong>la</strong>ss Joining {<br />

private static Test monitor = new Test();<br />

public static void main(String[] args) {<br />

Sleeper<br />

sleepy = new Sleeper("Sleepy", 1500),<br />

grumpy = new Sleeper("Grumpy", 1500);<br />

Joiner<br />

dopey = new Joiner("Dopey", sleepy),<br />

doc = new Joiner("Doc", grumpy);<br />

grumpy.interrupt();<br />

}<br />

} /


Sectiones Críticas<br />

Un synchronized sobre un objeto:<br />

• Sirven para crear regiones críticas. Por ejemplo:<br />

synchronized(syncObject) {<br />

}<br />

// This co<strong>de</strong> can be accessed<br />

// by only one thread at a time


Wait and notify<br />

Se pue<strong>de</strong>n utilizar sobre un objeto sincronizado.<br />

c<strong>la</strong>ss Or<strong>de</strong>r {<br />

private static int i = 0;<br />

private int count = i++;<br />

public Or<strong>de</strong>r() {<br />

if(count == 10) {<br />

System.out.println("Out of food, closing");<br />

System.exit(0);<br />

}<br />

}<br />

public String toString() { return "Or<strong>de</strong>r " + count; }<br />

}<br />

c<strong>la</strong>ss WaitPerson extends <strong>Thread</strong> {<br />

private Restaurant restaurant;<br />

public WaitPerson(Restaurant r) {<br />

restaurant = r;<br />

start();<br />

}<br />

public void run() {<br />

while(true) {<br />

while(restaurant.or<strong>de</strong>r == null)<br />

synchronized(this) {<br />

try {<br />

wait();<br />

} catch(InterruptedException e) {<br />

throw new RuntimeException(e);<br />

}<br />

}<br />

System.out.println(<br />

"Waitperson got " + restaurant.or<strong>de</strong>r);<br />

restaurant.or<strong>de</strong>r = null;<br />

}<br />

}<br />

}<br />

c<strong>la</strong>ss Chef extends <strong>Thread</strong> {<br />

private Restaurant restaurant;<br />

private WaitPerson waitPerson;<br />

public Chef(Restaurant r, WaitPerson w) {<br />

restaurant = r;<br />

waitPerson = w;<br />

start();<br />

}<br />

public void run() {<br />

while(true) {<br />

if(restaurant.or<strong>de</strong>r == null) {<br />

restaurant.or<strong>de</strong>r = new Or<strong>de</strong>r();<br />

System.out.print("Or<strong>de</strong>r up! ");<br />

synchronized(waitPerson) {<br />

waitPerson.notify();<br />

}<br />

}<br />

try {<br />

sleep(100);<br />

} catch(InterruptedException e) {<br />

throw new RuntimeException(e);<br />

}<br />

}<br />

}<br />

}<br />

public c<strong>la</strong>ss Restaurant {<br />

private static Test monitor = new Test();<br />

Or<strong>de</strong>r or<strong>de</strong>r; // Package access<br />

public static void main(String args[]) {<br />

Restaurant restaurant = new Restaurant();<br />

WaitPerson waitPerson = new WaitPerson(restaurant);<br />

Chef chef = new Chef(restaurant, waitPerson);<br />

}<br />

} ///:~

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!