Tema 04. Conceptos Básicos de Concurrencia en Java: Gregorio Quintana ©
Tema 04. Conceptos Básicos de Concurrencia en Java: Gregorio Quintana ©
Tema 04. Conceptos Básicos de Concurrencia en Java: Gregorio Quintana ©
MT1024
Programación
Concurrente y
Paralela
G. Quintana
Tema 04.
Conceptos
Básicos
Java y Hebras
join
en Java
sleep
Thread-safe
Cesión de
CPU
Curso 2020–21
( 1/ 44)
EI1024
MT1024
Programación
Concurrente y Contenido
Paralela
G. Quintana
Tema 04.
Conceptos
Básicos 1 Java y Hebras
sleep
4 Duérmete un Rato con el Método sleep
Thread-safe
Errores
Habituales
5 Código a Prueba de Hebras (thread-safe)
Hebras
Depend. y 6 Errores Habituales Básicos
Hebras
Independ.
Cesión de
7 Hebras Dependientes y Hebras Independientes
CPU
8 Cesión de CPU
( 2/ 44)
EI1024
MT1024
Programación
Concurrente y Bibliografía
Paralela
G. Quintana
Tema 04.
Conceptos
Básicos
Creación y
Oaks. Capítulo 2 “Thread Creation and Management”.
Arranque
Hebras
Depend. y
Herbert Schildt.
Hebras
Independ.
“Java: A Beginner’s Guide, Seventh Edition”.
Cesión de McGraw-Hill Education, 2017.
CPU
Capítulo 11 “Multithreaded Programming”.
( 3/ 44)
EI1024
MT1024
Programación
Concurrente y Un Problema Típico
Paralela
G. Quintana
Tema 04.
Conceptos
Básicos
Creación y
Arranque Un usuario compra un ordenador con 8 núcleos para
join ejecutar más rápidamente un código en Java que realiza
sleep dicho cálculo.
Thread-safe
Cesión de
CPU
¿Cuántos núcleos trabajan cuando lo ejecuta?
( 4/ 44)
EI1024
MT1024
Programación
Concurrente y Objetivos
Paralela
G. Quintana
Tema 04.
Conceptos
Básicos
Ser capaz de realizar tareas básicas (sin comunicación ni
sincronización) en las que se aprovechen los beneficios de
la concurrencia y el paralelismo.
Java y Hebras
Creación y
Arranque
1 Ser capaz de crear hebras.
join
Hebras
Depend. y ayuda de varias hebras. −→ Concurrencia.
Hebras
Independ.
Cesión de
Ejemplo 2: Una aplicación multihebra en la que se
CPU emplean varios núcleos/procesadores para evaluar una
función en múltiples puntos. −→ Paralelismo.
( 5/ 44)
EI1024
MT1024
Programación
Concurrente y
Paralela
G. Quintana
Tema 04.
Conceptos
Básicos
Java y Hebras
Creación y
Arranque
join
sleep
Thread-safe
Java y Hebras
Errores
Habituales
Hebras
Depend. y
Hebras
Independ.
Cesión de
CPU
( 6/ 44)
EI1024
MT1024
Programación
Concurrente y Java y Hebras
Paralela
G. Quintana
Tema 04.
Conceptos
Básicos
Java es un lenguaje diseñado para la concurrencia desde el
principio. No es un añadido a posteriori como en otros
Java y Hebras
lenguajes.
Creación y
Arranque La concurrencia está muy integrada dentro de Java: Todo
join objeto es un monitor (concepto de programación
sleep concurrente).
Thread-safe
Tema 04.
Conceptos
Básicos
Aunque no se empleen hebras explícitamente, éstas pueden
estar siendo empleadas dentro de la aplicación:
Java y Hebras
AWT y Swing.
Creación y
Arranque
Crean una hebra, llamada hebra event-dispatching, que
join
procesa todos los eventos.
sleep TimerTask.
Thread-safe Permite ejecutar tareas periódicamente.
Servlets y Páginas JavaServer.
Errores
Habituales
Tema 04.
Conceptos
Básicos
Cuando un usuario ejecuta un programa en Java, el S.O.
crea un proceso.
Java y Hebras Normalmente, este proceso crea a su vez a la hebra
Creación y principal, la cual ejecuta el programa principal.
Arranque
join
Usuario Hebra
sleep Proceso
ejecuta programa principal
Thread-safe
Errores
Habituales
Hebras
Por tanto, el programa principal es ejecutado también por
Depend. y
Hebras
una hebra. Dicha hebra se llama la hebra principal.
Independ.
La hebra principal podría después crear otras hebras.
Cesión de
CPU En este caso, se habla de una aplicación multihebra.
En este caso, todas las hebras están dentro del mismo
proceso.
( 9/ 44)
EI1024
MT1024
Programación
Concurrente y Java y Hebras (Cont.)
Paralela
G. Quintana
Tema 04.
Conceptos
Básicos
join
Cuerpo principal del resto de hebras: método run.
sleep
Una hebra termina si se cumple alguna de las siguientes
condiciones:
Thread-safe
Errores
Habituales 1 La hebra alcanza el final de su cuerpo principal.
Hebras
Depend. y
2 Se produce una excepción no contemplada (acceso a un
Hebras elemento fuera de un vector, desbordamiento, etc.).
Independ.
Cesión de
3 etc.
CPU
( 10/ 44)
EI1024
MT1024
Programación
Concurrente y Introducción a la Compartición de Información
Paralela
G. Quintana
Tema 04.
Conceptos
Básicos
La compartición de información es muy útil, pero también
es la principal causa de errores.
Java y Hebras
Creación y
Se abordará en profundidad en los temas siguientes.
Arranque
( 11/ 44)
EI1024
MT1024
Programación Introducción a la Compartición de Información
Concurrente y
Paralela
G. Quintana
(Cont.)
Tema 04.
Conceptos
Información en el montículo:
Básicos Las variables de instancia y las variables de clase
pueden ser compartidas (si se desea), dado que se
Java y Hebras almacenan siempre en el montículo.
Creación y
Arranque Información en la pila:
join
Cada hebra tiene su pila propia, no accesible al resto.
sleep
Por tanto, las variables locales de los métodos no se
Thread-safe
pueden compartir.
Errores
Habituales Nota: Si se declara como variable local una referencia a un
Hebras objeto, la referencia no puede ser compartida. En cambio,
el objeto al que apunta la variable local se crea en el
Depend. y
Hebras
Independ.
montículo, por lo que que sí podría ser compartido.
Cesión de
CPU
1 public void metodo1 ( int a ) {
2 int b = 123;
3 MiObjeto c = new MiObjeto () ;
4 }
( 12/ 44)
EI1024
MT1024
Programación
Concurrente y
Paralela
G. Quintana
Tema 04.
Conceptos
Básicos
Java y Hebras
Creación y
Arranque
join
Errores
Habituales
Hebras
Hebras
Depend. y
Hebras
Independ.
Cesión de
CPU
( 13/ 44)
EI1024
MT1024
Programación
Concurrente y Creación y Arranque de Hebras
Paralela
G. Quintana
Tema 04.
Conceptos
Básicos
( 14/ 44)
EI1024
MT1024
Programación
Concurrente y Creación y Arranque de Hebras (Cont.)
Paralela
G. Quintana
Tema 04.
Conceptos
Ejemplo básico: El siguiente código crea una hebra, la cual
Básicos ejecuta su método run.
Java y Hebras 1 /*
Creación y 2 // Clase del sistema . No teclear esta clase .
Arranque 3 class Thread {
join 4 ...
sleep 5 public void run () {
Thread-safe
6 }
7 ...
Errores
Habituales 8 }
Hebras 9 */
Depend. y 10 class EjemploCreacion1 {
Hebras
Independ. 11 public static void main ( String args [] ) {
Cesión de
12 Thread t = new Thread () ;
CPU 13 t . start () ;
14 System . out . println ( " Fin de programa . " ) ;
15 }
16 }
( 15/ 44)
EI1024
MT1024
Programación
Concurrente y Formas de Creación de Hebras
Paralela
G. Quintana
Tema 04.
Conceptos
Básicos
Java y Hebras
El método run de la clase Thread está vacío. Por tanto,
Creación y no ejecuta nada y no hace nada útil.
Arranque
Hebras
1 Dentro de una subclase de la clase Thread.
Depend. y
Hebras 2 Dentro de una clase que implemente la interfaz Runnable.
Independ.
( 16/ 44)
EI1024
MT1024
Programación
Concurrente y Primera Forma: A partir de una subclase de Thread
Paralela
G. Quintana
Tema 04.
Conceptos Ejemplo: Creación de una hebra como un objeto de una
Básicos
subclase de Thread.
Java y Hebras
1 class MiHebra extends Thread {
Creación y
Arranque 2 public void run () {
join
3 for ( int i = 0; i < 1000; i ++ ) {
4 System . out . println ( " Hola " ) ;
sleep
5 }
Thread-safe
6 }
Errores 7 }
Habituales
8
Hebras
Depend. y 9 class EjemploCreacion2a {
Hebras 10 public static void main ( String args [] ) {
Independ.
11 MiHebra t = new MiHebra () ;
Cesión de
CPU
12 t . start () ;
13 // new MiHebra () . start () ;
14 }
15 }
( 17/ 44)
EI1024
MT1024
Programación
Concurrente y Segunda Forma: A partir de una interfaz Runnable
Paralela
G. Quintana
Tema 04.
Conceptos Ejemplo: Creación de una hebra a partir de un objeto
Básicos
Thread y un objeto con método run:
Java y Hebras
1 class MiRun implements Runnable {
Creación y
Arranque 2 public void run () {
join
3 for ( int i = 0; i < 1000; i ++ ) {
4 System . out . println ( " Hola " ) ;
sleep
5 }
Thread-safe
6 }
Errores 7 }
Habituales
8
Hebras
Depend. y 9 class EjemploCreacion2b {
Hebras 10 public static void main ( String args [] ) {
Independ.
11 Thread t = new Thread ( new MiRun () ) ;
Cesión de
CPU
12 t . start () ;
13 // new Thread ( new MiRun () ) . start () ;
14 }
15 }
( 18/ 44)
EI1024
MT1024
Programación
Concurrente y Tercera Forma: Con clases anónimas
Paralela
G. Quintana
Tema 04.
Conceptos
Básicos
Ejemplo: Creación de una hebra con una clase anónima:
Java y Hebras
1 class EjemploCreacion2c {
Creación y
Arranque 2 public static void main ( String args [] ) {
join 3
sleep
4 Thread t = new Thread () {
5 public void run () {
Thread-safe
6 for ( int i = 0; i < 1000; i ++ ) {
Errores
Habituales
7 System . out . println ( " Hola " ) ;
8 }
Hebras
Depend. y 9 }
Hebras 10 };
Independ.
11 t . start () ;
Cesión de
CPU 12 }
13 }
( 19/ 44)
EI1024
MT1024
Programación
Concurrente y El Arranque es Obligatorio
Paralela
G. Quintana
Tema 04.
Conceptos
Básicos Para poner en marcha una hebra, son obligatorios dos
pasos: Creación y arranque.
Java y Hebras
Creación y
Arranque: El método start pone a la hebra a ejecutar su
Arranque método run, pero no espera a que termine.
join
sleep
Por tanto, el método start es la clave del solapamiento.
Thread-safe Los métodos start y run son dos métodos estándares de
Errores
Habituales
la clase Thread.
Hebras
El método start no se redefine; run, sí se redefine.
Depend. y
Hebras
Independ.
Para ahorrar un paso, dentro del constructor se puede
Cesión de
realizar el arranque con el método start. Así, en la misma
CPU creación ya se arranca la hebra. No recomendable.
Despiste habitual: Olvidar la invocación al método start.
( 20/ 44)
EI1024
MT1024
Programación
Concurrente y Arranque y Solapamiento
Paralela
G. Quintana
Errores
Habituales
main hebra t0 hebra t1
...
Hebras t0.start();
Depend. y
Hebras t1.start();
Independ. pepe();
Concurrencia
...
Cesión de
CPU
Tema 04.
Conceptos ¿Cuál es la diferencia entre que el programa principal
Básicos
ejecute t.run() o ejecute t.start()?
Java y Hebras
public static void main( ... ) { public static void main( ... ) {
Creación y
Arranque
... ...
t.run(); t.start();
join ... ...
} }
sleep
Hebras
Depend. y Concurrencia
Hebras
Independ.
Cesión de
CPU
Tema 04.
Conceptos El constructor permite pasar información fácilmente a las
Básicos
hebras (antes de que arranquen). Dicha información puede
Java y Hebras
actuar como si fueran parámetros: trabajo a realizar,
Creación y
identificador, etc.
Arranque
Tema 04.
Conceptos
Básicos
Java y Hebras
Creación y
Arranque
join
sleep
Espera a que Termine una
Thread-safe
Errores
Habituales
Hebra con el Método join
Hebras
Depend. y
Hebras
Independ.
Cesión de
CPU
( 24/ 44)
EI1024
MT1024
Programación Espera a que Termine una Hebra con el Método
Concurrente y
Paralela
G. Quintana
join
Tema 04.
Conceptos El método join detiene a la hebra llamadora hasta que la
Básicos
hebra ha terminado.
Java y Hebras
1 // Crea y arranca la hebra .
Creación y
Arranque
2 MiHebra t = new MiHebra () ;
3 t . start () ;
join
4 // La siguiente sentencia se ejecutar á
sleep
5 // concurrentemente al " run " de la hebra .
Thread-safe 6 ...
Errores 7 // Espera a que la hebra " t " termine .
Habituales
8 t . join () ;
Hebras
Depend. y
Tema 04.
Conceptos
Básicos Cuando una hebra o el programa principal realiza la
llamada t.join(), pueden ocurrir dos cosas:
Java y Hebras
Creación y
1 La hebra t ha terminado. ¿Qué ocurre en este caso?
Arranque
2 La hebra t no ha terminado. ¿Qué ocurre en este caso?
join
sleep
Todas las variantes del método join pueden activar la
Thread-safe
excepción InterruptedException.
Errores
Habituales Por ello, es conveniente tratarla:
Hebras
Depend. y 1 try {
Hebras
Independ. 2 t . join () ;
Cesión de 3 } catch ( Interrupt edException ex ) {
CPU 4 ex . printStackTrace () ;
5 }
( 26/ 44)
EI1024
MT1024
Programación
Concurrente y El Método join frente al Método isAlive
Paralela
G. Quintana
Tema 04.
Conceptos El método isAlive() devuelve cierto si una hebra está
Básicos
viva.
Este método no es bloqueante.
Java y Hebras
Creación y
Arranque
Ejemplo: Implementación ineficiente del método join
join sobre una hebra t empleando el método isAlive.
sleep
Tema 04.
Conceptos
Básicos 1 // Declaraci ó n y creaci ó n del vector de hebras .
2 MiHebra vh [] = new MiHebra [ numHebras ];
3
Java y Hebras 4 // Creaci ó n de las hebras .
Creación y
5 for ( int i = 0; i < numHebras ; i ++ ) {
Arranque 6 vh [ i ] = new MiHebra ( i ) ;
join
7 }
8
sleep 9 // Arranque de las hebras .
Thread-safe 10 for ( int i = 0; i < numHebras ; i ++ ) {
Errores
11 vh [ i ]. start () ;
Habituales 12 }
13
Hebras
Depend. y 14 // Espera a que todas las hebras terminen .
Hebras 15 for ( int i = 0; i < numHebras ; i ++ ) {
Independ.
16 try {
Cesión de 17 vh [ i ]. join () ;
CPU 18 } catch ( I n t e r r u p t e d E x c e p t i o n ex ) {
19 ex . p ri n tS ta ck T ra ce () ;
20 }
21 }
( 28/ 44)
EI1024
MT1024
Programación
Concurrente y
Paralela
G. Quintana
Tema 04.
Conceptos
Básicos
Java y Hebras
Creación y
Arranque
join
sleep
Duérmete un Rato con el
Thread-safe
Errores
Habituales
Método sleep
Hebras
Depend. y
Hebras
Independ.
Cesión de
CPU
( 29/ 44)
EI1024
MT1024
Programación
Concurrente y Duérmete un Rato con el Método sleep
Paralela
G. Quintana
Tema 04.
Conceptos
Básicos
Una hebra que ejecute el método Thread.sleep( n ) se
duerme durante aproximadamente n milisegundos.
Java y Hebras
¿La hebra dormirá exactamente n milisegundos? No.
Creación y
Arranque 1 Algunos Sistemas Operativos (SO) asignan una siesta
join mínima de entre 20 y 50 milisegundos.
sleep 2 Cuando la hebra despierta, todas las CPUs podrían estar
Thread-safe ocupadas. Justo antes de despertarse, algunos SO suben
Errores temporalmente la prioridad a la hebra para que coja
Habituales
rápidamente la CPU.
Hebras
Depend. y 3 La hebra puede ser despertada a mitad del sueño por
señales del SO u otros eventos.
Hebras
Independ.
Cesión de
CPU Ejemplo:
( 30/ 44)
EI1024
MT1024
Programación
Concurrente y Interrupción del Sueño
Paralela
G. Quintana
Tema 04.
Conceptos
Básicos Durante la ejecución de todas las variantes del método
sleep, se puede activar la excepción
Java y Hebras InterruptedException. Por ello, es conveniente tratarla:
Creación y
Arranque
join 1 try {
2 Thread . sleep ( 300 L ) ;
sleep
3 } catch ( Interrup tedException ex ) {
Thread-safe
4 ex . printStackTrace () ;
Errores 5 }
Habituales
Hebras
Depend. y
Hebras La ejecución del catch indica que la hebra ha sido
Independ.
despertada antes de tiempo.
Cesión de
CPU
Importante: No es conveniente basar el correcto
funcionamiento de un programa en el método sleep.
( 31/ 44)
EI1024
MT1024
Programación
Concurrente y
Paralela
G. Quintana
Tema 04.
Conceptos
Básicos
Java y Hebras
Creación y
Arranque
join
sleep
Código a Prueba de Hebras
Thread-safe
Errores
Habituales
(thread-safe)
Hebras
Depend. y
Hebras
Independ.
Cesión de
CPU
( 32/ 44)
EI1024
MT1024
Programación
Concurrente y Código a Prueba de Hebras (thread-safe)
Paralela
G. Quintana
Tema 04.
Conceptos
Creación y
Arranque
1 Debe funcionar correctamente en aplicaciones monohebra
join
(una sola hebra).
sleep 2 Debe funcionar correctamente en aplicaciones multihebra
Thread-safe
(más de una hebra).
Errores
Habituales Para ello debe funcionar bien independientemente de la
Hebras velocidad relativa, planificación y temporización de las
Depend. y
Hebras hebras.
Independ.
Cesión de
Además, no debe permitir a las hebras caer en estados
CPU incorrectos o inválidos, ni violar precondiciones,
postcondiciones ni invariantes.
( 33/ 44)
EI1024
MT1024
Programación
Concurrente y
Paralela
G. Quintana
Tema 04.
Conceptos
Básicos
Java y Hebras
Creación y
Arranque
join
sleep
Hebras
Depend. y
Hebras
Independ.
Cesión de
CPU
( 34/ 44)
EI1024
MT1024
Programación
Concurrente y Error Habitual Básico: Compartición Inadvertida
Paralela
G. Quintana
Tema 04.
Conceptos
Básicos
Java y Hebras
Creación y
Ejercicio: ¿Qué ocurrirá si las hebras (objetos de la clase
Arranque MiHebra) imprimen en pantalla el valor a.id?
join
sleep
1 Trabajo a = new Trabajo () ;
Thread-safe
2 for ( i = 0; i < n ; i ++ ) {
Errores 3 a . id = i ;
Habituales
4 new MiHebra ( a ) . start () ;
Hebras
Depend. y 5 }
Hebras
Independ.
Cesión de
CPU
( 35/ 44)
EI1024
MT1024
Programación
Concurrente y Error Habitual Básico: Compartición Supuesta
Paralela
G. Quintana
Tema 04.
Conceptos
Básicos
Ejercicio: Supongamos que dos hebras de la siguiente clase
(con los valores de miId adecuados) arrancan
Java y Hebras
simultáneamente. ¿Qué aparece en pantalla?
Creación y
Arranque 1 class MiHebra extends Thread {
join 2 int miId , valor ;
sleep 3 public MiHebra ( int miId ) {
4 this . miId = miId ;
Thread-safe
5 }
Errores 6 public void run () {
Habituales
7 if ( miId == 0 ) {
Hebras
Depend. y
8 valor = 10;
Hebras 9 } else if ( miId == 1 ) {
Independ. 10 d u e r m e t e D u r a n t e M i l i s e g u n d o s ( 2000 L ) ;
Cesión de 11 System . out . println ( " valor : " + valor ) ;
CPU
12 }
13 }
14 }
( 36/ 44)
EI1024
MT1024
Programación Error Habitual Básico: Suposiciones sobre la
Concurrente y
Paralela
G. Quintana
Velocidad
Tema 04.
Conceptos
Básicos
( 37/ 44)
EI1024
MT1024
Programación
Concurrente y
Paralela
G. Quintana
Tema 04.
Conceptos
Básicos
Java y Hebras
Creación y
Arranque
join
Errores
Habituales
Hebras Independientes
Hebras
Depend. y
Hebras
Independ.
Cesión de
CPU
( 38/ 44)
EI1024
MT1024
Programación
Concurrente y Método setDaemon
Paralela
G. Quintana
Tema 04.
Conceptos
Básicos
Una hebra del tipo daemon es una hebra (auxiliar) cuya
única función es ayudar a otras.
Creación y
Arranque hebras de este tipo.
Dicho de otra forma: Un programa Java termina cuando
join
sleep
Thread-safe
todas sus hebras no daemon han terminado.
Errores
Habituales Ejemplo de uso:
Hebras
Depend. y 1 public static void main ( String args [] ) {
Hebras
Independ. 2 MiHebra t = new MiHebra () ;
Cesión de
3 t . setDaemon ( true ) ;
CPU 4 t . start () ;
5 System . out . println ( " Fin del main . " ) ;
6 }
( 39/ 44)
EI1024
MT1024
Programación
Concurrente y Método setDaemon (Cont.)
Paralela
G. Quintana
Tema 04.
Conceptos
Básicos
Es conveniente fijar el tipo (y otras características) antes
de que la hebra arranque.
Java y Hebras
Creación y
Arranque
Herencia: Por defecto (si no se emplea setDaemon), una
join
hebra hereda el tipo de su hebra creadora.
sleep
El programa principal es del tipo no daemon.
Thread-safe
Hebras
Depend. y daemon.
Hebras
Independ.
Cesión de
El método System.exit( -1 ) termina siempre, tanto si
CPU hay funcionando hebras dependientes como
independientes.
( 40/ 44)
EI1024
MT1024
Programación
Concurrente y
Paralela
G. Quintana
Tema 04.
Conceptos
Básicos
Java y Hebras
Creación y
Arranque
join
sleep
Hebras
Depend. y
Hebras
Independ.
Cesión de
CPU
( 41/ 44)
EI1024
MT1024
Programación
Concurrente y Cesión de CPU con el Método yield
Paralela
G. Quintana
Tema 04.
Conceptos
Básicos
El estándar de Java no indica nada al respecto de un
quantum máximo de tiempo tras el cual una hebra pierde
Java y Hebras la CPU para dejarla a otra.
Creación y
Arranque Por tanto, el estándar ni obliga a que exista dicho
join quantum, ni obliga a que no exista.
sleep
Thread-safe
Por ello, si una hebra está realizando mucho cálculo
Errores
intensivo y ninguna operación de E/S, se recomienda que
Habituales
de vez en cuando (no a todas horas) ceda la CPU, por si
Hebras
Depend. y hay otras hebras listas.
Hebras
Independ.
Si la hebra no cede la CPU y se ejecuta en un
Cesión de
CPU mononúcleo-monoprocesador, puede que dicha hebra
retrase a las demás o incluso podría llegar a producir un
interbloqueo (deadlock).
( 42/ 44)
EI1024
MT1024
Programación
Concurrente y Cesión de CPU con el Método yield (Cont.)
Paralela
G. Quintana
Tema 04.
Conceptos
Básicos
join
1 Si hay otra hebra en estado listo, la CPU puede pasar a
sleep ésta y la hebra original pasará al estado listo.
Thread-safe 2 Si no hay otra hebra en estado listo, la hebra que ha
Errores llamado al método yield continuará en ejecución.
Habituales
Hebras
Depend. y En resumen, la ejecución del método yield activa al
Hebras
Independ.
planificador (scheduler ) y éste puede elegir a otra hebra o
Cesión de no.
CPU
( 43/ 44)
EI1024
MT1024
Programación
Concurrente y Cesión de CPU con el Método yield (Cont.)
Paralela
G. Quintana
Tema 04.
Conceptos
Básicos
sleep Puede esperar a que todas las demás hebras hayan tomado
Thread-safe un quantum, o a que hayan tomado un quantum sólo las
Errores hebras con la misma prioridad, etc.
Habituales
Hebras
Depend. y
No es obligatorio usar el método yield en todas las
Hebras
Independ.
aplicaciones, pero en algunos casos es muy recomendable
Cesión de
e incluso necesario.
CPU
( 44/ 44)