Vous êtes sur la page 1sur 40

SCJP 6

Clase 9 Threads

Ezequiel Aranda
Sun Microsystems Campus
Ambassador

Disclaimer & Acknowledgments


>Even though Ezequiel Aranda is a full-time employee of Sun
Microsystems, the contents here are created as his own
personal endeavor and thus does not reflect any official
stance of Sun Microsystems.
>Sun Microsystems is not responsible for any inaccuracies in
the contents.
>Acknowledgments The slides of this presentation are made
from SCJP Unit 9 by Warit Wanwithu and Thanisa
Kruawaisayawan and SCJP Workshop by P. Srikanth.
>This slides are Licensed under a Creative Commons
Attribution Noncommercial Share Alike 3.0
>http://creativecommons.org/licenses/by-nc-sa/3.0/

AGENDA
>java.lang.Thread
>java.lang.Runnable
>Instanciacin e inicializacin
de hilos
>Planificacin
>Estados de los hilos
>Sincronizacin, locks y
deadlocks
>Interaccin entre hilos

Extendiendo java.lang.Thread
>Sobrescribir el mtodo run(). Debera ser algo
as:
class MyThread extends Thread {
public void run() {
System.out.println("Important
job running in MyThread"); } }

>La limitacin de este enfoque es que al


extender Thread, no podremos extender
ninguna otra clase.

Extendiendo java.lang.Thread (II)


>Podemos tambin sobrecargar el mtodo run():
class MyThread extends Thread {
public void run() {
System.out.println("Important job
running in MyThread"); }
public void run(String s) {
System.out.println("String in run is "
+ s); } }

>Sin embargo, dicho mtodo ser ignorado por la


clase Thread salvo que lo llamemos nosotros
mismos y ser ejecutado como un mtodo normal.

Implementando java.lang.Runnable
>Implementando Runnable podremos,
adicionalmente, extender de otra clase.
class MyRunnable implements Runnable{
public void run() {
System.out.println("Important
job running in MyRunnable");
}

Instanciando un Thread
>Si extendemos la clase Thread:
MyThread t = new MyThread()

>Si implementamos la interfaz Runnable,


tambin necesitaremos una instancia de
Thread:
MyRunnable r = new MyRunnable();
Thread t = new Thread(r);

>Suele pensarse en Thread como el obrero y


Runnable como el trabajo.

Instaciando un thread (II)


>Existen varios constructores en la clase
Thread:
>Thread()
>Thread(Runnable target
>Thread(Runnable target, String name)
>Thread(String name)

Inicializando un Thread
t.start();

>Y que pasa cuando llamamos a start()?


>Se inicializa un nuevo hilo de ejecucin (con su
stack de llamadas propio).
>El estado de dicho hilo pasa de new a
runnable.
>Cuando se le de la posibilidad de ejecutarse, se
ejecutar su mtodo run().

Inicializando un Thread: Aclaraciones


>Llamar explicitamente a un mtodo run() solo
har que se invoque al mtodo run() del hilo
que se encuentra en ejecucin actualmente.
>El siguiente cdigo no inicializa un nuevo hilo
de ejecucin (aunque es cdigo legal):
Runnable r = new Runnable();
r.run();

El planificador de threads
>El orden en el cual se ejecutar un conjunto
de threads no est garantizado.
class NameRunnable implements Runnable {
public void run() {
for (int x = 1; x <= 3; x++) {
System.out.println("Run by " +
Thread.currentThread().getName()
+ ", x is " + x);
}
}
}

Estados de un Thread
>New: es el estado en el que se encuentra el
hilo apenas despus de su creacin. En este
punto no se considera que el hilo este vivo.
>Runnable: que un hilo se encuentre en este
estado significa que es elegible para su
ejecucin, pero el planificador an no lo ha
seleccionado. En este punto se considera que
el hilo esta vivo.

Estados de un Thread (II)


>Running: que un hilo est en este estado
significa que el planificador lo ha
seleccionado para ser el hilo en ejecucin.
>Waiting/ Blocked/ Sleeping: en cualquiera de
estos estados, el hilo est vivo, pero no es
elegible para ejecucin. Puede volver al
estado runnable en cualquier momento.

Estados de un Thread (III)


t.sleep() o t.yield()

>Se encuentran definidas para afectar al hilo


que se encuentra en ejecucin.
>Debemos recordar que un hilo bloqueado se
considera vivo an.

Estados de un Thread (IV)


>Dead: una vez que el hilo ha muerto, no
puede revivirse. Invocar start() en un thread
muerto resultar en una exception.
WAITING
o
BLOCKED

NEW

RUNNABLE

RUNNING

DEAD

Sleeping
>sleep() es un mtodo esttico de la clase
Thread.
>Se usa para frenar a un hilo forzandolo a ir al
estado sleeping por una fraccin de tiempo
dada antes de volver a ser elegible para
ejecucin.
try {
Thread.sleep(20*60*1000); //powernap
}
catch (InterruptedException ex) { }

Sleeping (II)
class NameRunnable implements Runnable {
public void run() {
for (int x = 1; x < 4; x++) {
System.out.println("Run by "+
Thread.currentThread().getName());
try {Thread.sleep(1000); }
catch (InterruptedException ex) { }
}
}
}

>Sleep es una forma de dar a todos los hilos la


posibilidad de ejecutarse.

yield()
>La idea de yield() es la de cambiar el estado
del hilo en ejecucin a runnable, dandole as
la posibilidad de ejecutarse a otros hilos de la
misma prioridad.
>Sin embargo, nada prohbe al planificador
volver a seleccionar para ejecucin al mismo
hilo una y otra vez.

join()
>Si un hilo B necesita que la tarea de un hilo A
se complete para poder comenzar su
ejecucin, necesitamos hacer un join entre
B y A.
>Esto har que B no pueda pasar al estado
runnable hasta que A complete su ejecucin y
pase al estado dead.

join() (II)

En resumen
>sleep(): garantiza que el hilo en ejecucin
pase al estado sleeping por al menos el
tiempo especificado.
>yield(): no garantiza absolutamente nada. Su
funcin es la de volver al hilo en ejecucin al
estado runnable.
>join(): provoca que se detenga la ejecucin
del hilo actual hasta, por lo menos, la
finalizacin del hilo con el que se realiz el
join.

Sincronizacin
>Existe un problema conocido como race condition
>Se da cuando mltiples hilos que pueden acceder a un
mismo recurso.
>Produce datos corruptos cuando los hilos acceden al valor
de los datos entremedio de operaciones que deberan ser
atmicas.

Sincronizacin(II)
>No hay forma de garantizar que un mismo
hilo se mantendr en ejecucin durante toda
la operacin atmica.
>Pero s es posible garantizar que incluso si el
hilo no se mantiene en ejecucin durante la
operacin atmica, ningn otro hilo pueda
actuar sobre los mismos datos.

Sincronizacin (III)
>Entonces Cmo protegemos nuestros
datos?
>Debemos hacer dos cosas
>Hacer privadas a las variables
>Sincronizar el cdigo que modifica las variables.
(utilizando la palabra reservada synchronized).

>Ejemplo:
private synchronized void
makeWithdrawal(int amt)

Sincronizacin y locks
>Cada objeto en java tiene un lock, que se
utiliza cuando el mismo tiene cdigo marcado
como synchronized en alguno de sus
mtodos.
>Cuando ingresamos en un mtodo
sincronizado, no esttico, obtenemos
automticamente el lock de la instancia de la
clase cuyo cdigo estamos ejecutando.

Sincronizacin y locks (II)


>Dado que cada objeto solo tiene un lock, si un
hilo ha obtenido dicho lock, ningn otro hilo
podr obtenerlo hasta que el primero lo
libere.
>Si una clase tiene mtodos sincronizados y
mtodos no sincronizados, mltiples hilos
pueden an acceder a los mtodos no
sincronizados.
>Cuando un hilo pasa a estar dormido,
retiene todos sus locks.

Sincronizacin y locks (III)


>Se puede reducir el tamao de las partes
sincronizadas a un bloque (en vez de un mtodo
completo).
>En una muestra de originalidad propia del equipo de
diseo de Stacy Malib, esto se bautiz bloque
sincronizado.
class SyncTest {
public void doStuff() {
System.out.println("not synchronized");
synchronized(this) {
System.out.println("synchronized"); } } }

Sincronizacin y locks (IV)


public synchronized void doStuff() {
System.out.println("synchronized");
}

>Es equivalente a:
public void doStuff() {
synchronized(this) {
System.out.println("synchronized");
}
}

Mtodos estticos sincronizados


>Slo hay una copia de los datos estticos, por
lo que har falta un lock para la clase
completa para sincronizar mtodos estticos.
public static int getCount() {
synchronized(MyClass.class) {
return count;
}
}

Qu sucede si un hilo no puede


obtener un lock?
>Bsicamente, el hilo va a parar a una especie
de pool para dicho lock, en donde esperar a
que se libere el lock y el hilo pueda volver al
estado runnable.
>Al liberarse un lock, no hay forma de
garantizar que un hilo en particular sea el
que lo obtenga a continuacin.
>Ni siquiera hay forma de garantizar que el hilo
que espero por ms tiempo sea el que lo obtenga.

Qu sucede si un hilo no puede


obtener un lock? (II)

>Dos hilos que llaman a mtodos


sincronizados, no estticos de la misma clase
solo se bloquearan uno al otro si se invocan
sobre la misma instancia. En caso contrario
obtendrn un lock cada uno.
>En el caso de los mtodos estticos, los hilos
siempre competirn por el mismo lock.
>Un mtodo esttico y uno no esttico no se
bloquearn uno al otro, nunca.

Qu sucede si un hilo no puede


obtener un lock? (III)

>Para los bloques sincronizados, debemos fijarnos en


cual fue el objeto utilizado en el cerrojo (dentro de
los parntesis que se encuentran luego de la palabra
synchronized).
>Los hilos que utilizan el mismo objeto se bloquearn
entre ellos. Los que utilizan distintos objetos, no.

Entonces, cundo necesito


sincronizar?

>Simple: cuando un mtodo que ser usado


por varios hilos accede a valores
modificables.
>El acceso a campos estticos debe ser hecho
desde mtodos estticos sincronizados.
>El acceso a campos no estticos sincronizados
debe ser hecho desde mtodos no estticos
sincronizados.

Thread Safe
>Cuando los mtodos de una clase han sido
cuidadosamente sincronizados para proteger
los datos de la misma, llamamos a esa clase
Thread Safe.
>Por ejemplo los mtodos de StringBuffer se
encuentran sincronizados, mientras que los
de StringBuilder no lo estn. Esto hace que en
un ambiente multithread sea ms seguro
utilizar StringBuffer.

Deadlock
>Un deadlock ocurre cuando dos hilos se
bloquean mutuamente esperando que el otro
libere el lock que cada uno necesita.
>Ninguno puede
continuar su ejecucin
hasta que el otro libere
el lock por el que
espera, por lo que se
sientan a esperar para
siempre

Interaccin entre hilos


>La clase Object tiene tres mtodos: wait(),
notify() y notifyAll(), que ayudan a los hilos a
comunicar el estado de los eventos que les
interesan.
>Un punto clave para el examen es recordar
que cualquiera de estos mtodos debe ser
llamado desde un contexto sincronizado. Un
hilo no puede invocar wait o notify en un
objeto salvo que posea el lock de dicho
objeto.

class ThreadA {
public static void main(String [] args) {
ThreadB b = new ThreadB();
b.start();
synchronized(b) {
try {
System.out.println("Waiting for b
to
complete...");
b.wait();
}
catch (InterruptedException e) {}
System.out.println("Total is:
" +
b.total);
}
}
}

class ThreadB extends Thread {


int total;
public void run() {
synchronized(this) {
for(int i=0;i<100;i++) {
total += i;
}
notify();
}
}
}

Usando notifyAll() cuando varios hilos


estn esperando
>Podemos utilizar notifyAll() en el objeto para
permitir que todos los hilos salgan del rea de
espera y vuelvan al estado runnable.
>De esta forma nos aseguramos que el thread
correcto (junto con todos los otros) sea
notificado.

Preguntas

Vous aimerez peut-être aussi