java scjp clase9
TRANSCRIPT
-
8/18/2019 Java SCJP clase9
1/40
SCJP 6Clase 9 – Threads
Ezequiel Aranda
Sun Microsystems Campus
Ambassador
-
8/18/2019 Java SCJP clase9
2/40
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 inthe 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/
-
8/18/2019 Java SCJP clase9
3/40
AGENDA
> java.lang.Thread
> java.lang.Runnable
> Instanciación e inicialización
de hilos
> Planificación
> Estados de los hilos
>
Sincronización, locks ydeadlocks
> Interacción entre hilos
-
8/18/2019 Java SCJP clase9
4/40
Extendiendo java.lang.Thread
> Sobrescribir el método run(). Debería ser algo
así:
class MyThread extends Thread {
public void run() {
System.out.println("Important
job running in MyThread"); } }
>
La limitación de este enfoque es que alextender Thread, no podremos extender
ninguna otra clase.
-
8/18/2019 Java SCJP clase9
5/40
Extendiendo java.lang.Thread (II)
> Podemos también sobrecargar el método run():
class MyThread extends Thread {
public void run() {
System.out.println("Important jobrunning in MyThread"); }
public void run(String s) {
System.out.println("String in run is "
+ s); } }
>
Sin embargo, dicho método será ignorado por la
clase Thread salvo que lo llamemos nosotros
mismos y será ejecutado como un método normal.
-
8/18/2019 Java SCJP clase9
6/40
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");
}
-
8/18/2019 Java SCJP clase9
7/40
Instanciando un Thread
> Si extendemos la clase Thread:
MyThread t = new MyThread()
> Si implementamos la interfaz Runnable,
también 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”.
-
8/18/2019 Java SCJP clase9
8/40
Instaciando un thread (II)
> Existen varios constructores en la clase
Thread:
>
Thread()
>
Thread(Runnable target> Thread(Runnable target, String name)
>
Thread(String name)
-
8/18/2019 Java SCJP clase9
9/40
Inicializando un Thread
t.start();
> ¿Y que pasa cuando llamamos a start()?
>
Se inicializa un nuevo hilo de ejecución (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 método run().
-
8/18/2019 Java SCJP clase9
10/40
Inicializando un Thread: Aclaraciones
> Llamar explicitamente a un método run() solo
hará que se invoque al método run() del hilo
que se encuentra en ejecución actualmente.
>
El siguiente código no inicializa un nuevo hilode ejecución (aunque es código legal):
Runnable r = new Runnable();
r.run();
-
8/18/2019 Java SCJP clase9
11/40
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
-
8/18/2019 Java SCJP clase9
12/40
Estados de un Thread
> New: es el estado en el que se encuentra el
hilo apenas después de su creación. En este
punto no se considera que el hilo este “vivo”.
>
Runnable: que un hilo se encuentre en esteestado significa que es elegible para su
ejecución, pero el planificador aún no lo ha
seleccionado. En este punto se considera que
el hilo esta vivo.
-
8/18/2019 Java SCJP clase9
13/40
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 ejecución.
>
Waiting/ Blocked/ Sleeping: en cualquiera deestos estados, el hilo está vivo, pero no es
elegible para ejecución. Puede volver al
estado runnable en cualquier momento.
-
8/18/2019 Java SCJP clase9
14/40
Estados de un Thread (III)
t.sleep() o t.yield()
> Se encuentran definidas para afectar al hilo
que se encuentra en ejecución.
>
Debemos recordar que un hilo bloqueado se
considera vivo aún.
-
8/18/2019 Java SCJP clase9
15/40
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.
NEW
WAITING
o
BLOCKED
RUNNABLE RUNNING DEAD
-
8/18/2019 Java SCJP clase9
16/40
Sleeping
> sleep() es un método estático de la clase
Thread.
> Se usa para frenar a un hilo forzandolo a ir al
estado “sleeping” por una fracción de tiempodada antes de volver a ser elegible para
ejecución.try {
Thread.sleep(20*60*1000); //powernap
}
catch (InterruptedException ex) { }
-
8/18/2019 Java SCJP clase9
17/40
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.
-
8/18/2019 Java SCJP clase9
18/40
yield()
> La idea de yield() es la de cambiar el estado
del hilo en ejecución a runnable, dandole así
la posibilidad de ejecutarse a otros hilos de la
misma prioridad.> Sin embargo, nada prohíbe al planificador
volver a seleccionar para ejecución al mismo
hilo una y otra vez.
-
8/18/2019 Java SCJP clase9
19/40
join()
> Si un hilo B necesita que la tarea de un hilo A
se complete para poder comenzar su
ejecución, necesitamos hacer un “join” entre
B y A.> Esto hará que B no pueda pasar al estado
runnable hasta que A complete su ejecución y
pase al estado dead.
-
8/18/2019 Java SCJP clase9
20/40
join() (II)
-
8/18/2019 Java SCJP clase9
21/40
En resumen…
> sleep(): garantiza que el hilo en ejecución
pase al estado “sleeping” por al menos el
tiempo especificado.
>
yield(): no garantiza absolutamente nada. Sufunción es la de volver al hilo en ejecución al
estado “runnable”.
>
join(): provoca que se detenga la ejecución
del hilo actual hasta, por lo menos, la
finalización del hilo con el que se realizó el
join.
-
8/18/2019 Java SCJP clase9
22/40
Sincronización
> Existe un problema conocido como “race condition”
>
Se da cuando múltiples hilos que pueden acceder a un
mismo recurso.
>
Produce datos corruptos cuando los hilos acceden al valor
de los datos entremedio de operaciones que deberían seratómicas.
-
8/18/2019 Java SCJP clase9
23/40
Sincronización(II)
> No hay forma de garantizar que un mismo
hilo se mantendrá en ejecución durante toda
la operación atómica.
>
Pero sí es posible garantizar que incluso si elhilo no se mantiene en ejecución durante la
operación atómica, ningún otro hilo pueda
actuar sobre los mismos datos.
-
8/18/2019 Java SCJP clase9
24/40
Sincronización (III)
> Entonces… ¿Cómo protegemos nuestros
datos?
> Debemos hacer dos cosas
>
Hacer privadas a las variables
> Sincronizar el código que modifica las variables.
(utilizando la palabra reservada synchronized).
> Ejemplo:
private synchronized void
makeWithdrawal(int amt)
-
8/18/2019 Java SCJP clase9
25/40
Sincronización y locks
> Cada objeto en java tiene un lock, que se
utiliza cuando el mismo tiene código marcado
como synchronized en alguno de sus
métodos.> Cuando ingresamos en un método
sincronizado, no estático, obtenemos
automáticamente el lock de la instancia de la
clase cuyo código estamos ejecutando.
-
8/18/2019 Java SCJP clase9
26/40
Sincronización y locks (II)
>
Dado que cada objeto solo tiene un lock, si un
hilo ha obtenido dicho lock, ningún otro hilo
podrá obtenerlo hasta que el primero lo
libere.> Si una clase tiene métodos sincronizados y
métodos no sincronizados, múltiples hilos
pueden aún acceder a los métodos no
sincronizados.
>
Cuando un hilo pasa a estar “dormido”,
retiene todos sus locks.
-
8/18/2019 Java SCJP clase9
27/40
Sincronización y locks (III)
>
Se puede reducir el tamaño de las partes
sincronizadas a un bloque (en vez de un método
completo).
>
En una muestra de originalidad propia del equipo de
diseño de Stacy Malibú, esto se bautizó “bloque
sincronizado”.class SyncTest {
public void doStuff() {
System.out.println("not synchronized");
synchronized(this) {
System.out.println("synchronized"); } } }
-
8/18/2019 Java SCJP clase9
28/40
Sincronización y locks (IV)
public synchronized void doStuff() {
System.out.println("synchronized");
}
>
Es equivalente a: public void doStuff() {
synchronized(this) {
System.out.println("synchronized");
}
}
-
8/18/2019 Java SCJP clase9
29/40
Métodos estáticos sincronizados
>
Sólo hay una copia de los datos estáticos, por
lo que hará falta un lock para la clase
completa para sincronizar métodos estáticos.
public static int getCount() {
synchronized(MyClass.class) {
return count;
}}
-
8/18/2019 Java SCJP clase9
30/40
¿Qué sucede si un hilo no puede
obtener un lock?
>
Básicamente, 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 continuación.
>
Ni siquiera hay forma de garantizar que el hilo
que espero por más tiempo sea el que lo obtenga.
-
8/18/2019 Java SCJP clase9
31/40
¿Qué sucede si un hilo no puede
obtener un lock? (II)>
Dos hilos que llaman a métodos
sincronizados, no estáticos de la misma clase
solo se bloquearan uno al otro si se invocan
sobre la misma instancia. En caso contrarioobtendrán un lock cada uno.
>
En el caso de los métodos estáticos, los hilos
siempre competirán por el mismo lock.
>
Un método estático y uno no estático no se
bloquearán uno al otro, nunca.
-
8/18/2019 Java SCJP clase9
32/40
¿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 paréntesis que se encuentran luego de la palabra
synchronized).
>
Los hilos que utilizan el mismo objeto se bloquearán
entre ellos. Los que utilizan distintos objetos, no.
-
8/18/2019 Java SCJP clase9
33/40
Entonces, ¿cuándo necesito
sincronizar?>
Simple: cuando un método que será usado
por varios hilos accede a valores
modificables.
>
El acceso a campos estáticos debe ser hechodesde métodos estáticos sincronizados.
> El acceso a campos no estáticos sincronizados
debe ser hecho desde métodos no estáticos
sincronizados.
-
8/18/2019 Java SCJP clase9
34/40
“Thread Safe”
>
Cuando los métodos de una clase han sido
cuidadosamente sincronizados para proteger
los datos de la misma, llamamos a esa clase
“Thread Safe”.> Por ejemplo los métodos de StringBuffer se
encuentran sincronizados, mientras que los
de StringBuilder no lo están. Esto hace que en
un ambiente multithread sea más seguroutilizar StringBuffer.
-
8/18/2019 Java SCJP clase9
35/40
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 ejecución
hasta que el otro libere
el lock por el queespera, por lo que se
sientan a esperar para
siempre…
-
8/18/2019 Java SCJP clase9
36/40
Interacción entre hilos
>
La clase Object tiene tres métodos: 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 métodos debe ser
llamado desde un contexto sincronizado. Un
hilo no puede invocar wait o notify en unobjeto salvo que posea el lock de dicho
objeto.
-
8/18/2019 Java SCJP clase9
37/40
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);
}
}
}
-
8/18/2019 Java SCJP clase9
38/40
class ThreadB extends Thread {
int total;
public void run() {
synchronized(this) {
for(int i=0;i
-
8/18/2019 Java SCJP clase9
39/40
Usando notifyAll() cuando varios hilos
están 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 threadcorrecto (junto con todos los otros) sea
notificado.
-
8/18/2019 Java SCJP clase9
40/40
Preguntas