Multithreading y Java
Ing. Gerardo Horvilleur simpleJ Comunidad Java Sun Java Champion
Multithreading
Un procesador ejecuta las instrucciones
secuencialmente una despus de la otra se le llama un Execution Thread (Hilo de Ejecucin)
A esta ejecucin secuencial de instrucciones Multithreading es cuando se estn
ejecutando varios threads simultneamente
Multithreading: Un CPU
Si un procesador ejecuta las instrucciones Realmente no puede hacerlo, pero puede
simular que lo hace. secuencialmente una despus de la otra... Cmo le hace para ejecutar varios threads simultneamente?
Multithreading: Un CPU
Run Queue
T T T T Ready to Run T Quantum Timeout T I/O Request Sleep Lock T T
Waiting
T T T
CPU (running)
I/O Request Lock
Multithreading: Priorities
Run Queues
Priorities: Higher Lower Ready to Run T T T T T T T T T T I/O Request Sleep Lock Quantum Timeout T
Waiting
T T T
T T
CPU (running)
I/O Request Lock
Multithreading: MultiCPU
Run Queues
Priorities: Higher Lower T T T
Waiting
T T T
T T
T T T
T T T T
CPU (running)
CPU (running)
CPU (running)
Multithreading: OS
Sistemas Operativos con soporte para multithreading:
AIX Linux Mac OS X Solaris Windows
Pero cada uno tiene su propio API de threads!
Multithreading:Ventajas
Aplicaciones con mejor tiempo de respuesta
(an en mquinas con un solo CPU) procesadores simultneamente
Permite que una aplicacin utilice varios Mejor aprovechamiento de la computadora
Ejemplo: Web Server
Abrir Server Socket Esperar Conexin Pausa Pausa Pausa Leer Solicitud del Socket Leer Pgina de Disco Mandar Respuesta
Ejemplo: Web Server
Esperar Conexin Leer Solicitud del Socket
No
(almacenar copia en memoria)
Leer Pgina de Disco
Pgina en Memoria? S Mandar Respuesta
Ejemplo: Web Server
Esperar Conexin Crear thread para atender solicitud Atender Solicitud Atender Solicitud
Atender Solicitud Atender Solicitud
Ejemplo: Web Server
Esperar Conexin Poner en la Cola
Thread Pool
T T
T T T
T T T T
T T
T T
Java y Multithreading
Java cuenta con soporte para threads en el
lenguaje y la JVM
Mismo API en cualquier sistema operativo
(hasta los mismos ejecutables!) opcional:
En muchos casos usar threads no es Swing Servlets y JSP
Java Threads
Para manipular threads desde Java se emplea
la clase Thread
new Thread();
Thread
Runnable
Una manera de decirle que hacer a un
public interface Runnable { void run(); }
Thread es por medio de una clase que implemente la interfaz Runnable
Runnable
public class HazAlgo implements Runnable { public void run() { while (true) [Link](algo); } } new Thread(new HazAlgo());
HazAlgo Thread
T
Start
Para iniciar la ejecucin de un Thread se
emplea el mtodo start()
new Thread(new HazAlgo()).start()
HazAlgo Thread
T
Demo1
public class Demo1 implements Runnable { private int delay; public Demo1(int d) delay = d; } public void run() { while (true) { [Link](delay); try { [Link](delay * 1000); } catch (InterruptedException e) { break; } } }
Demo1 (cont.)
public static void main(String[] args) { for (int i = 0; i <= 5; i++) new Thread(new Demo1(i)).start(); } }
Join
Se puede esperar a que un thread termine
de ejecutarse por medio del mtodo join()
Thread t = new Thread(new HazAlgo()); [Link](); [Link](); //esperar a que termine
Demo2
public class Demo2 implements Runnable { private int counter; public void incrCounter() { counter = counter + 1; } public int getCounter() { return counter; } public void run() { for (int i = 0; i < 1000000; i++) incrCounter(); }
Demo2 (cont.)
public static void main(String[] args) throws InterruptedException { Demo2 demo2 = new Demo2(); Thread[] threads = new Thread[5]; for (int i = 0; i < [Link]; i++) { threads[i] = new Thread(demo2); threads[i].start(); } for (int i = 0; i < [Link]; i++) threads[i].join(); [Link]([Link]()); } }
Accesos no controlados
Thread #1 Lee valor Incrementa valor Graba valor Lee valor Lee valor Incrementa valor Graba valor Thread #2
Incrementa valor Graba valor
Multiples Procesadores
CPU #1 Cache
Copia del valor
CPU #2 Cache
Copia del valor
Memoria
Valor
El problema es peor!
Locks (candados)
Cada objeto tiene un lock Slo un thread puede ser dueo de un
requiere adquirir un lock lock en un momento dado (un mismo thread puede ser dueo de varios locks)
El modicador synchronized indica cuando se Con synchronized tambin se garantiza la
sincrona en las jerarquas de memorias (caches)
Demo3
El modicador synchronized indica que se Si otro thread tiene el lock entonces se
public synchronized void incrCounter() { counter = counter + 1; }
debe adquirir el lock al entrar al mtodo y liberarlo al salir del mtodo detiene la ejecucin de este thread hasta que el otro lo libere
Cuidado!
El uso correcto de threads no implica
simplemente ponerle synchronized a todos los mtodos
Hay que entender lo que uno est haciendo
Demo4
public class Demo4 implements Runnable { private int counter; public synchronized int getCounter() { return counter; } public synchronized void setCounter(int v) { counter = v; } public void run() { for (int i = 0; i < 10000; i++) setCounter(getCounter() + 1); }
Entre el llamado a getCounter() y el llamado a setCounter() se libera el lock!
Synchronized statement
En ciertas ocasiones nos gustara obtener un
lock nicamente en una regin crtica de un mtodo (para permitir mayor concurrencia) synchronized statement
synchronized (expr) {
En estos casos se puede emplear un Sintaxis:
}
statements...
Synchronized Statement
El resultado de evaluar expr debe ser una
una manera sencilla de escribir un synchronized statement sobre el objeto actual Esto:
public synchronized void metodo() { }
referencia a un objeto (sobre el cual se va a adquirir el lock)
El modicador synchronized es simplemente
es equivalente a:
public void metodo() { synchronized (this) { } }
Demo5
public class Demo5 implements Runnable { int counter; public int getCounter() { return counter; } public void setCounter(int v) { counter = v; } public void run() { for (int i = 0; i < 10000; i++) synchronized (this) { setCounter(getCounter() + 1); } } }
Demo6
public class Demo6 implements Runnable { private Object obj1; private Object obj2; public Demo6(Object o1, Object o2) { obj1 = o1; obj2 = o2; } public void run() { for (int i = 0; i < 1000; i++) { synchronized (obj1) { synchronized (obj2) { [Link](i); } } } }
Demo6 (cont.)
public static void main(String[] args) { Object o1 = new Object(); Object o2 = new Object(); new Thread(new Demo6(o1, o2)).start(); new Thread(new Demo6(o2, o1)).start(); } }
Hay un deadlock! Un thread obtiene el lock sobre o1 y despus trata de obtener el lock sobre o2, pero el otro thread ya tiene ese lock y ahora quiere el lock que tiene el primer thread... Ctrl-\ para ver los threads y locks (Unix)
Cuidado!
Slo el cdigo dentro de un synchronized
est protegido por un lock... Los otros mtodos ignoran el lock.
Cuidado con variables public o protected
public int counter; public synchronized void incrCounter() { counter = counter + 1; }
y en otra clase:
[Link] = [Link] + 1; //Evita el lock!
Pertenecen a la clase y no a las instancias
public class Ejemplo { private static int counter; public synchronized void incrCounter() { counter = counter + 1; }
Variables static
Ejemplo
(clase) counter
Ejemplo
(instancia #1)
Ejemplo
(instancia #2)
Variables static
Dos posibles soluciones:
public static synchronized void incrCounter() { counter = counter + 1; }
o
public synchronized void incrCounter() { synchronized ([Link]) { counter = counter + 1; } }
Hay mucho ms!
Interrupcin de threads: interrupt, interrupted,
isInterrupted
Prioridades: setPriority, getPriority Coordinacin entre threads: wait, notify,
notifyAll
Background threads (daemons): setDaemon Y todava mucho ms...
Para saber ms
The Java Programming Language The Java Language Specication
Doug Lea Ken Arnold, James Gosling & David Holmes James Gosling, Bill Joy, Guy Steel & Gilad Bracha
Concurrent Programming in Java