Upload
others
View
2
Download
0
Embed Size (px)
Citation preview
Threads
LSUB
GSYC
6 de abril de 2016
(cc) 2015 Laboratorio de Sistemas,Algunos derechos reservados. Este trabajo se entrega bajo la licencia Creative Commons Reconocimiento -
NoComercial - SinObraDerivada (by-nc-nd). Para obtener la licencia completa, veasehttp://creativecommons.org/licenses/. Tambien puede solicitarse a Creative Commons, 559 Nathan Abbott Way,
Stanford, California 94305, USA.
Las imagenes de terceros conservan su licencia original.
Threads
I ¿Concurrencia?
I Un thread es un hilo de ejecucion.
I Una aplicacion tiene al menos un thread.
I Los threads de Java son expulsivos. La correspondencia entrethreads y procesos del OS depende de la implementacion.
I Antes de usar algo desde distintos threads debemosasegurarnos de que es thread-safe.
Thread
I La clase Thread proporciona la abstraccion.
I Hay dos formas de crear una instancia de Thread:
I Crear una clase que derive de la clase Thread.I Crear una clase que implemente la interfaz Runnable. Se
recomienda usar esta aproximacion: separar el trabajo (tuclase Runnable) del trabajador (la clase Thread). Ademas,puedes ser Runnable y extender otra clase distinta a Thread.
I El thread arranca cuando se invoca su metodo start().
Clase con interfaz Runnable
p u b l i c c l a s s Tweeter implements Runnable {
@ O v e r r i d ep u b l i c v o i d run ( ) {f o r ( i n t i = 0 ; i < 1 0 ; i ++)
System . out . p r i n t l n ( ” Thread s a y s t w e e e e e t ! ! ! ” ) ;}
p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) {f o r ( i n t i = 0 ; i < 1 0 ; i ++)
( new Thread ( new Tweeter ( ) ) ) . s t a r t ( ) ;}
}
Clase Thread anonima
p u b l i c c l a s s S e r v i d o r {
p u b l i c v o i d a t e n d e r ( ) {f i n a l Socket sk ;// . . . a c ep t a r l l amada en sk . . .new Thread ( ) {
p u b l i c v o i d run ( ) {s e r v i r C l i e n t e ( sk ) ;
} ;} . s t a r t ( ) ;
p r o t e c t e d v o i d s e r v i r C l i e n t e ( Socket sk ) {// . . .
}}
Thread
Thread proporciona varios metodos de clase interesantes:
I currentThread(): retorna la referencia al thread que estaejecutando.
I activeCount(): retorna el numero actual de threads activos.
I dumpStack(): vuelca la pila del thread actual en la salida deerrores.
I sleep(int ms): causa que el thread actual se bloqueedurante un tiempo.
I yield(): causa que el thread actual ceda su cuanto a otrothread.
System . out . p r i n t l n ( ” Thread ”+ Thread . c u r r e n t T h r e a d ( ) . g e t I d ( )+ ” S t a t e ”+ Thread . c u r r e n t T h r e a d ( ) . g e t S t a t e ( ) ) ;
Interrupciones
I Una interrupcion es una indicacion para que el thread deje dehacer lo que esta haciendo para hacer otra cosa.
I ¡No es aconsejable usar interrupciones!
I Normalmente los threads reaccionan acabando su ejecucion,retornando del metodo run().
Interrupciones
I Algunos metodos elevan una InterruptedException si seinterrumpe el thread mientras que ejecutan (p. ej. sleep()).
I Otros metodos bloqueantes no levantan la excepcion.
I Se puede comprobar si el thread ha sido interrumpidoinvocando Thread.interrupted() si no se invocan metodosque eleven una InterruptedException.
I ¡Ojo! Thread.interrupted() comprueba si ha sidointerrumpido pero limpia el estado de interrupcion si devuelvetrue.
Codigo
p u b l i c v o i d run ( ){. . .t r y {
. . .Thread . s l e e p ( 1 0 0 0 ) ;
. . .} catch ( I n t e r r u p t e d E x c e p t i o n e ) {
// E l th r ead ha s i d o i n t e r r ump i d o m i en t r a s dormia// y no ha dormido e l t iempo deseado . Retornamos// de run ( )
System . e r r . p r i n t l n ( ” Thread ”+ Thread . c u r r e n t T h r e a d ( ) . g e t I d ( )+” i n t e r r u p t e d , e x i t i n g . ” ) ;
r e t u r n ;}. . .
}
Codigo
t r y {. . .
/∗∗ S i e l t h r e ad ha s i d o i n t e r r ump i d o pero no ha s a l t a d o l a∗ excepc ion , dejamos que l o maneje e l ca tch l e van tando∗ no s o t r o s mismos l a e x c epc i on ! i n t e r r u p t e d ( ) l imp i a∗ e l es tado , pe ro e s t e throw l o pondra de nuevo .∗/i f ( Thread . i n t e r r u p t e d ( ) )
throw new I n t e r r u p t e d E x c e p t i o n ( ) ;. . .
} catch ( I n t e r r u p t e d E x c e p t i o n e ) {. . .
}
Join
I Se puede esperar a que un thread muera con join().
I Se le puede pasar un tiempo de espera.
Thread t = new Thread ( new Worker ( ) ) ;t . s t a r t ( ) ;
. . .
t . j o i n ( ) ;
Sincronizacion
I Si dos threads acceden al mismo recurso compartido sin estarsincronizados, tendremos una condicion de carrera.
I Java proporciona dos mecanismos basicos de sincronizacion:
I Metodos synchronized.I Sentencias synchronized.
Metodos synchronized
I Es un monitor.
I No es posible que dos invocaciones a metodos synchronized
del mismo objeto sean concurrentes.
I Si un thread esta ejecutando un metodo synchronized,cualquier otro thread que intente invocar un metodosynchronized de ese objeto se queda bloqueado hasta quepueda proceder.
I Los constructores no pueden ser synchronized (no tienesentido).
Metodos synchronized
I Internamente esta implementado mediante un lock (intrinsiclock o monitor lock).
I Toda instancia tiene asociada un monitor lock.
I Las clases tambien tienen su propio lock para sincronizar elacceso a los miembros de clase (metodos estaticossynchronized, etc.).
I Un thread que necesite acceso exclusivo a la instancia necesitaadquirir el lock y despues de acceder necesita soltar el lock. Alinvocar un metodo synchronized se adquiere el lockautomaticamente y se suelta al finalizar la invocacion (por unreturn o por una excepcion).
I Es un lock re-entrante: desde un metodo synchronized sepuede invocar a otro metodo synchronized.
Codigo
p u b l i c c l a s s Counter{p r i v a t e i n t c ;
p u b l i c s y n c h r o n i z e d i n t i n c r ( ) {r e t u r n ++c ;
}}
p u b l i c c l a s s Tweeter implements Runnable {p r i v a t e Counter c o u n t e r ;
p u b l i c Tweeter ( Counter c ){c o u n t e r = c ;
}
@ O v e r r i d ep u b l i c v o i d run ( ) {
f o r ( i n t i = 0 ; i < 1 0 ; i ++){System . out . p r i n t l n ( ” Thread ”
+ Thread . c u r r e n t T h r e a d ( ) . g e t I d ( )+ ” s a y s t w e e e e e t #”+ c o u n t e r . i n c r ( ) + ” ! ! ! ” ) ;
}}
}
Sentencias synchronized
I Se debe especificar el objeto del que se quiere adquirir el lock.
I Un metodo synchronized es lo mismo que ponersynchronized(this) alrededor de todo el metodo.
p u b l i c v o i d i n c r C o u n t e r ( S t r i n g name ) {s y n c h r o n i z e d ( t h i s ) {
count++;}
}
wait()
I wait() bloquea el thread, saliendo del monitor.
I ¡Siempre se debe comprobar la condicion antes de continuar!
// den t ro de un metodo s yn ch r on i z e d de l a c l a s e Serv :// un th r ead e s p e r a a que l l e g u e un c l i e n t e
w h i l e ( n c l i e n t s == 0) {t r y {
w a i t ( ) ;} catch ( I n t e r r u p t e d E x c e p t i o n e ) {
. . .}
}
notify()
I notify() despierta a un thread (cualquiera) de los que estanbloqueados en un wait, que competira por coger el lock delmonitor.
I notifyAll() despierta a todos.
I Solo debe invocarse desde dentro del monitor.
// den t ro de o t r o metodo s yn ch r on i z e d de l a c l a s e Serv :// l l e g a un c l i e n t e y se d e s p i e r t a a un th r ead// para que l o a t i e nd a
a d d C l i e n t ( c ) ;n c l i e n t s ++;n o t i f y A l l ( ) ;
Volatile
I Las variables volatile se leen/escriben de forma atomica.
I La escritura de una variable volatile fuerza una relacionpasa-antes-que: si un thread ve la variable modificada, ve elestado generado por cualquier accion previa del thread que lamodifico.
I Ojo: esto no nos protege de la mayorıa de las condiciones decarrera.
p u b l i c c l a s s Counter {p r i v a t e v o l a t i l e long count = 0 ;
p u b l i c v o i d i n c r e m e n t ( ) {count++; // CONDICION DE CARRERA ! ! !
}}
Executor
El paquete java.util.concurrent ofrece la interfaz Executor:
I Es una interfaz para lanzar nuevas tareas y evitar el idiompara crear un thread.
I Solo tiene un metodo, execute(). Los detalles de laejecucion dependen de la implementacion concreta de lainterfaz (ejecucion inmediata, esperar un worker, etc.).
I No hay forma de obtener el resultado de la tarea.
Estas dos sentencias pueden ser equivalentes:
( new Thread ( r ) ) . s t a r t ( ) ;
e . e x e c u t e ( r ) ;
ExecutorService
I Extiende la interfaz Executor con submit() que permitepasar objetos que implementen Runnable. Retorna un objetoFuture que sirve para consultar y controlar el progreso de latarea.
I shutdown() impide ejecutar nuevas tareas, pero deja que lasque estan en marcha puedan acabar.
I shutdownNow() acaba las tareas en marcha y retorna unalista de tareas que estaban esperando para ejecutar. No dagarantıas sobre lo que pasara (si terminaran, se pararan, etc.).
I awaitTermination() se bloquea hasta que termine elproceso de shutdown o salte el timeout.
I La clase Executors proporciona factory methods para losdistintos ExecutorServices.
ExecutorService
E x e c u t o r S e r v i c e p o o l = E x e c u t o r s . newFixedThreadPool ( 1 0 ) ;. . .p o o l . e x e c u t e ( new C l i e n t M g r ( ) ) ;. . .p o o l . shutdown ( ) ;i f ( ! p o o l . a w a i t T e r m i n a t i o n ( 6 0 , TimeUnit . SECONDS) ) {
p o o l . shutdownNow ( ) ;i f ( ! p o o l . a w a i t T e r m i n a t i o n ( 6 0 , TimeUnit . SECONDS) )
System . e r r . p r i n t l n ( ” Pool d i d not t e r m i n a t e ” ) ;}
Futures
I El metodo submit() permite pasar al executor una clase queimplemente Runnable.
I Retorna un objeto Future que sirve para consultar y controlarel progreso de la tarea.
I El metodo get() del Future se bloquea y retorna nullcuando la tarea ha terminado.
ExecutorService
E x e c u t o r S e r v i c e p o o l = E x e c u t o r s . newFixedThreadPool ( 1 0 ) ;
Future<?> f u t u r e = p o o l . submit ( new Runnable ( ) {p u b l i c v o i d run ( ){
t r y {Thread . s l e e p ( 2 0 0 0 ) ;
} catch ( I n t e r r u p t e d E x c e p t i o n e ) {e . p r i n t S t a c k T r a c e ( ) ;
}}
} ) ;
i f ( f u t u r e . g e t ( ) == n u l l )System . out . p r i n t l n ( ” Termino ok ” ) ;
ExecutorService
I El metodo submit() tambien permite pasar objetos queimplementen Callable.
I Un objeto Callable debe implementar un metodo call()
que retorna un valor.
I El valor retornado por call() se obtiene con el metodoget() del objeto Future.
ExecutorService
E x e c u t o r S e r v i c e p o o l = E x e c u t o r s . newFixedThreadPool ( 1 0 ) ;
Future<S t r i n g > f u t u r e = p o o l . submit ( new C a l l a b l e <S t r i n g >(){p u b l i c S t r i n g c a l l ( ) throws E x c e p t i o n {
System . out . p r i n t l n ( ” Hola ! ! ” ) ;r e t u r n ”He t e r m i n a d o b i e n ! ! ” ;
}} ) ;
System . out . p r i n t l n ( ” Cadena de s a l i d a de l a t a r e a : ”+ f u t u r e . g e t ( ) ) ;
Colecciones concurrentes
El paquete java.util.concurrent proporciona clases con estasinterfaces:
I BlockingQueue: FIFOs bloqueantes, ya las conocemos.
I ConcurrentMap: Diccionarios (nombre-valor) con operacionesatomicas.
BlockingQueue
I Es una cola para comunicar procesos.
I Amplıa la interfaz Queue con operaciones bloqueantes.
BlockingQueue
p u b l i c i n t e r f a c e BlockingQueue<E> extends Queue<E> {boolean put (E e ) ; // como add , pe ro b loqueaE t a k e ( ) ; // como e lement ( ) , pe ro b loquea
}
BlockingQueue
I Bloqueantes sin timeout:I put(e): inserta un elemento.I take(): elimina la cabeza y la devuelve.
I Bloqueantes con timeout:I offer(e, time, unit): inserta un elemento.I poll(time, unit): elimina la cabeza y la devuelve.
Thread-safeness
I Podemos crear una coleccion envuelta con decorators parahacerla thread-safe.
I Para ello podemos usar los metodos de Collections
synchronizedSet o synchronizedMap
p u b l i c s t a t i c <T> Set<T> s y n c h r o n i z e d S e t ( Set<T> s ) ;
I Por ejemplo:
Set s = C o l l e c t i o n s . s y n c h r o n i z e d S e t ( new HashSet ( ) ) ;