0% encontró este documento útil (0 votos)
94 vistas20 páginas

Multitarea en Java

El documento describe la programación multitarea en Java utilizando subprocesos o threads. Existen dos formas de crear threads: extendiendo la clase Thread o implementando la interfaz Runnable. La clase Thread contiene métodos como run(), start(), join(), interrupt() y sleep() para controlar la ejecución de los threads. El ejemplo crea threads de ambas formas y los ejecuta para imprimir iteraciones de un ciclo while.

Cargado por

edilsonguillin
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
94 vistas20 páginas

Multitarea en Java

El documento describe la programación multitarea en Java utilizando subprocesos o threads. Existen dos formas de crear threads: extendiendo la clase Thread o implementando la interfaz Runnable. La clase Thread contiene métodos como run(), start(), join(), interrupt() y sleep() para controlar la ejecución de los threads. El ejemplo crea threads de ambas formas y los ejecuta para imprimir iteraciones de un ciclo while.

Cargado por

edilsonguillin
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 20

Multitarea en Java EDUCACIÓN DIGITAL

Índice

1 | Programación multitarea 3

2 | La clase Thread y la interfaz Runnable 4

3 | Subprocesos. Ciclo de vida 8

4 | Finalización de subprocesos 12

5 | Sincronización 14

6 | Comunicación de subprocesos: 17
notify, notifyAll y wait

7 | Suspender, reanudar y detener subprocesos 18


Multitarea en Java | TELEFÓNICA / 3

1. Programación multitarea
La programación multitarea en Java consiste en organizar un programa para que realice más de una
tarea a la vez, dividir el programa en subprocesos que pueden ejecutarse concurrentemente si se
dispone de más de un procesador o compartiendo el tiempo del procesador.

En Java los subprocesos en los que se puede organizar un programa Un programa Un programa con varios subprocesos:
se llaman “threads” Un “thread” es un flujo de control secuencial con un subproceso Subflujo 1: dos threads
Subflujo 2: tres threads
dentro de un programa. Los programas vistos hasta este momento
no son multitarea, sólo tienen un flujo de control, sólo existe un SUBFLUJO 1
único “thread”.

Todos los programas tienen al menos un subproceso de ejecución,


es el llamado subproceso principal, es el que se ejecuta al iniciarse
el programa. Hasta este momento es el único que se ha utilizado. A
partir de este subproceso principal se crean los demás.

SUBFLUJO 2

IMAGEN 12.1: MULTITAREA EN JAVA, SUBPROCESOS O THREADS.


Multitarea en Java | TELEFÓNICA / 4

La implementación en Java de la multitarea basada en procesos se En el método run es donde tiene lugar la acción del subproceso,
basa en la clase Thread y en la interfaz Runnable. es donde se define el código que ejecutará el subproceso. Dentro
del método run puede invocar otras funciones, usar otras clases y
declarar variables al igual que el subproceso principal.
Object

Thread <<interface>>
Runnable

+ run():void

IMAGEN 12.2: CLASE THREAD E INTERFAZ RUNNABLE.

2. La clase Thread y la interfaz Runnable


Hay dos modos de proporcionar el método run a un subproceso: La razón de que existan estas dos posibilidades es porque en Java no
existe la herencia múltiple. Si una clase deriva de otra no podemos
• En una subclase de Thread sobrepasando el método run.
hacer que derive también de Thread.
• En cualquier clase implementando el interface Runnable y
definiendo su función run.
Multitarea en Java | TELEFÓNICA / 5

Creando una subclase de Thread o


implementando Runnable sería básicamente
de la forma siguiente: public class Subproceso extends Thread {
//public class Subproceso implements Runnable{
public Subproceso(String nombre) {
super(nombre);
}
public void run(){
//definir run...
}
}

//En otro código, por ejemplo una función main


//se crean diferentes subprocesos
public static void main(String [] args){
Subproceso subproceso1 = new Subproceso(“Subproceso 1”);
Subproceso subproceso2 = new Subproceso(“Supproceso 2”);
//otras sentencias
subproceso1.start();//start inicia el proceso llamando a run
subproceso2.start();//start inicia el proceso llamando a run
//new Thread(subproceso1).start();
//new Thread(subproceso2).start();
//otras sentencias
}
Multitarea en Java | TELEFÓNICA / 6

Los principales métodos definidos en la clase Thread son los que se


indican en la tabla siguiente:

Método Funcionalidad
void run() Punto de inicio del subproceso.
void start() Inicia la ejecución de un subproceso
invocando a su método run().
final void join() Se detiene el actual y espera a que
termine otro subproceso.
final void interrupt() Interrumpe el subproceso.
final String getName() Obtiene el nombre de un subproceso.
final setName(String nombre) Define el nombre del subproceso.
long getId() Devuelve el ID del subproceso, long
generado cuando se creó.
final String getPriority() Obtiene la prioridad de un subproceso.
final setPriority(int prioridad) Cambia la prioridad del subproceso.
final boolean isAlive() Obtiene true si un subproceso sigue en
ejecución.
final boolean isInterrupted() Obtiene true si un subproceso ha sido
interrumpido.
static void sleep(long milis) Suspende un subproceso durante los
milisegundos especificados.
static Thread currentThread() Devuelve una referencia al subproceso
que se esta ejecutando.
Thread.State getState() Devuelve el estado actual del
subproceso.

Tabla 12.1: Métodos de la clase Thread.


Multitarea en Java | TELEFÓNICA / 7

En el ejemplo siguiente, se crean dos clases de “threads”, uno con


subclase de Thread, otro implementando Runnable. Se crean dos
objetos de cada tipo y se lanza su ejecución con run. En cada run public class ClaseRunnable implements Runnable{
se ejecuta un código de información de que thread es un número private int n;
determinado de veces. public ClaseRunnable(int n){
this.n=n;
}
@Override
public void run() {
public class ClaseThread extends Thread { int i = 1;
private int n; while (true) {
public ClaseThread(int n) { System.out.println(“Run del thread “+
getClass().getSimpleName()
this.n = n;
+”. Iteracion “ + i++);
}
if (i > n) {
public void run() {
break;
int i = 1; }
while (true) { }
System.out.println(“Run del thread “ + }
this.getName() public static void main(String[] args) {
+ “ de “ + getClass().getSimpleName() Random aleatorio = new Random();
+ “ con ID “ ClaseThread t1= new ClaseThread(aleatorio.
+ this.getId() + “. Iteracion “ + nextInt(5)+1);
i++); ClaseThread t2= new ClaseThread(aleatorio.
if (i > n) { nextInt(6)+1);
ClaseRunnable r1=
break;
new
} ClaseRunnable(aleatorio.nextInt(4)+1);
} ClaseRunnable r2=
} new
ClaseRunnable(aleatorio.nextInt(7)+1);
t1.start();
t2.start();
new Thread(r1).start();
new Thread(r2).start();
}
Multitarea en Java | TELEFÓNICA / 8

3. Subprocesos. Ciclo de vida


Un subproceso desde que se crea como objeto “runnable”, hasta que se libera el espacio que ocupa en
memoria, pasa por una serie de estados. Los estados de un subproceso son los que están indicados
en la enumeración Thread.State. La función static getState() de Thread devuelve el estado actual del
subproceso en ejecución.
Los estados de un proceso son: De acuerdo con estos estados, la imagen siguiente muestra cual es
ciclo de vida de un subproceso.

Estado Funcionalidad
new Thread()
NEW Se ha creado el subproceso pero todavía no ha
start()
arrancado. finalize()

RUNNABLE El subproceso se está ejecutando en la JVM. De run() finaliza run()


NEW RUNNABLE TERMINATED
acuerdo con el planificador de tareas (scheduler)
scheduling
del sistema operativo está en ejecución o
preparado para seguir ejecutándose, de acuerdo
a su prioridad, ocupando un “slice” de tiempo del READY RUNNING
procesador. El planificador de tareas tiene que scheduling
asegurar que todos los subprocesos en este yield()
estado tienen que llegar a ejecutarse.
BLOCKED El subproceso se encuentra bloqueado, wait()
BLOCKED
notify()

esperando a volver a ejecución. wait()


WAITING El subproceso se encuentra esperando join() notify()
WAITING
indefinidamente, a que otro realice una sleep(tiempo)
terminación normal
determinada acción que lo saque de este estado. wait(tiempo)
join(tiempo)
TIMED_ El subproceso se encuentra esperando durante TIMED_WAITING
WAITING un tiempo determinado.
TERMINATED terminación normal
El subproceso ha finalizado su ejecución, ha
terminado la función run.
IMAGEN 12.2: CICLO DE VIDA DE UN SUBPROCESO.
Tabla 12.2: Estado de un subproceso.
Multitarea en Java | TELEFÓNICA / 9

Los subprocesos en Java después de ser creados pasan al estado • Cuando desde otro subproceso se invoca a la función Thread.
“NEW” y cuando se les invoca la función start pasan a “RUNNABLE”. join, el subproceso actual, pasa al estado “WAITING”. Permanece
En este estado, es cuando se ejecuta el método run, pero en en este hasta que el otro subproceso termina.
programación multitarea y concurrente, el tiempo del procesador se
• Cuando desde otro subproceso en un bloque sincronizado, se
reparte entre los subprocesos en este estado, de tal manera que se
invoca a la función wait , el subproceso actual, pasa al estado
garantice que todo subproceso se ejecuta.
“BLOCKED”. Permanece en este hasta que desde otro subproceso
se invoca la función notify.
El planificador de tareas (“scheduler”) es quien cuando a los
subprocesos les llega su turno, por la prioridad que tengan • Si el subproceso actual recibe la función yield, si esta en
establecida, los pasa a “RUNNING”, estando en este estado el tiempo “RUNNING”, pasa a “READY”. esto significa que deja la ejecución
de procesador correspondiente (“slice”) y cuando acabe dicho tempo y pasa a la cola de subprocesos en espera de volver a ejecución.
pasan a “READY”. Así seguirá cada subproceso hasta que termine la
• Si desde un subproceso se invoca a la función interrupt del
ejecución de run, pasando a “TERMINATED” o se produzca algunas
subproceso actual y este esta en “WAITING” o “TIME_WAITING”,
de las situaciones siguientes:
se produce la interrupción InterruptException, se procesa el
• En método run, se ejecuta la función Thread.sleep, el subproceso bloque catch que pudiera tener asociada, y a continuación sigue
cambia a “TIMED_WAITING”. Permanece en este hasta que con la ejecución de run que quedara.
terminan los milisegundos pasados como parámetro a esta
función.
• Cuando desde otro subproceso se invoca a las funciones wait, el
subproceso actual, pasa al estado “WAITING”. Permanece en este
hasta que desde otro subproceso se invoque la función notify.
Tanto wait como notify son funciones heredadas de Object.
Multitarea en Java | TELEFÓNICA / 10

En el ejemplo se siguiente se crean dos subprocesos y se cambia su


estado con función sleep y se provoca su parada con interrupt. do{ } while(!( p1.getState() ==
Thread.State.TERMINATED &&
p2.getState() == Thread.State.
TERMINATED));
System.out.println(“ESTADO DE “+p1.
public static void main(String[] args) getName()+
throws InterruptedException { “ ===> “+ p1.getState());
Prueba p1 = new Prueba(“---thread 1---”); System.out.println(“FINALIZACION: “ +
Prueba p2 = new Prueba(“---thread 2---”); System.currentTimeMillis());
System.out.println(“ESTADO DE “+p1. }
getName()+
“ ===> “+
p1.getState());
System.out.println(“COMIENZO: “ + System.
currentTimeMillis());
p1.start();
System.out.println(“ESTADO DE “+p1.
getName()+
“ ===> “+ p1.getState());
p2.start();
Thread.sleep(100);
p1.interrupt();
Thread.sleep(100);
p1.interrupt();
p2.interrupt();
Thread.sleep(100);
p2.interrupt();
int i=0;
Multitarea en Java | TELEFÓNICA / 11

La función run de estos subprocesos es la siguiente: Las funciones run y main son miembro de la misma clase que
hereda de Thread:

public void run() {


for (int i = 1; i <= 3; i++) { package com.juan.threads02.interrup;
System.out.println(“INICIO DE CICLO “+ i + public class Prueba extends Thread {
“ DE “ + getName() + “ ===> “+ private long inicio;
(System.currentTimeMillis() - inicio) public Prueba(String str) {
+ “ milisegundos”); super(str);
try { inicio = System.currentTimeMillis();
Thread.sleep(1000); }
} public void run() { /*sentencias*/ }
catch (InterruptedException e) { public static void main(String[] args)
System.out.println(“INTERRUMPIDO: “ + throws InterruptedException { /*sentencias*/
getName() }
+ “ ===> “ + (System. }
currentTimeMillis() - inicio)
+ “ milisegundos”);
}
finally {
System.out.println(“FIN DE CICLO
“+ i +
“ DE “ + getName() + “ ===> “

+ (System.
currentTimeMillis() - inicio)
+ “ milisegundos”);
}
}
}
Multitarea en Java | TELEFÓNICA / 12

4. Finalización de subprocesos
Para saber si un subproceso ha finalizado se puede utilizar la función isAlive(), devuelve true si
aún no ha finalizado y sigue en ejecución. En el código siguiente se utiliza para que el proceso principal
(función main) finalice en cuanto finalicen los tres subprocesos que se arrancan en este.

mt3.thread.isAlive());
System.out.println(“Finaliza la función
public static void main(String args[]) {
main”);
System.out.println(“Comienza función main”);
}
MiThread mt1 = new MiThread(“Subproceso
#1”);
MiThread mt2 = new MiThread(“Subproceso
#2”); También se puede esperar que finalice un subproceso utilizando la
MiThread mt3 = new MiThread(“Subproceso función join(). Esta función hace que el subproceso que invoque a
#3”); join de otro subproceso se quede esperando hasta que este finalice.
do { Por ejemplo, si en la función main se invoca a join de otro subproceso,
System.out.print(“.”); el código de la función main se queda esperando hasta que finalice
try { el subproceso para el que se invoca join. En realidad, es unir a la vida
Thread.sleep(100); de un subproceso a la de otro u otros, de ahí su nombre.
}
catch(InterruptedException exc) {
System.out.println(“Interrumpido en
main.”);
}
} while (mt1.thread.isAlive() ||
mt2.thread.isAlive() ||
Multitarea en Java | TELEFÓNICA / 13

Sus formas son: En el ejemplo el subproceso de main espera a que finalicen tres
subprocesos a los que invoca join.
public final void join() throws InterruptedException
try {
También se puede usar con estas dos formas, en las que se
mt1.thread.join();
espera a que finalice o que pase el tiempo establecido en los
parámetros. System.out.println(“Subproceso #1 se ejecuta join.”);
public final void join(long millis) throws mt2.thread.join();
InterruptedException System.out.println(“Subproceso #2 se ejecuta join.”);
public final void join(long millis, int nanos) throws mt3.thread.join();
InterruptedException System.out.println(“Subproceso #3 se ejecuta join.”);
} catch (InterruptedException exc) {
System.out.println(“Interrumpido main”);
}
System.out.println(“Finaliza la función main”);
Multitarea en Java | TELEFÓNICA / 14

5. Sincronización
Cuando varios subprocesos están accediendo al mismo recurso puede ocurrir lo que se denomina lecturas
erróneas. Por ejemplo, si un subproceso debe actualizar el valor de una variable, si ese cambio todavía no
se ha producido y otro subproceso ha leído dicho valor, el resultado es que el segundo subproceso está
trabajando con un dato erróneo, lo correcto hubiese sido esperar a que el primer subproceso actualizase
el valor, para que el segundo lo leyera.

Tres subprocesos tienen que acceder a lista para añadir, borrrar o recorrer sus elementos
Para evitar esto se utiliza la sincronización, implementada en Java
con la palabra reservada synchronized, que permite sincronizar una
función o un bloque de código. Así si un primer subproceso accede
thread01 lista.add(numero); Lista al método o código sincronizado bloquea a los demás subprocesos.
Cuando el subproceso finaliza su ejecución desbloquea a los demás
thread02 lista.remove(); 45 52 83 23 para que uno pueda acceder.
thread03 lista.listarTodos();
En el código siguiente, el método sumarArray esta sincronizado.
Dos subprocesos en su función run invocan a este método, por tanto
Se puede “proteger” acceso no simultáneo con “syncronized” o la zona de memoria o
al método que acceda a dicha zona de memoria.
sólo uno está ejecutando el código de sumarArray, el otro espera a
que el anterior acabe.
synchonized public void listarTodos() synchonized(lista){
for (Integer numero: lista){ lista.add(numero);
System.out. }
println(numero);
}
synchonized(lista){
}
lista.remove();
}

IMAGEN 12.3: SINCRONIZACIÓN CON SYNCHRONIZED.


Multitarea en Java | TELEFÓNICA / 15

public void run() {

class SumarArray { int suma;


private int suma; System.out.println(thread.getName() + “
synchronized int sumarArray(int nums[]) { EMPEZANDO”);
suma = 0; suma = sa.sumarArray(numeros);
for (int i = 0; i < nums.length; i++) { System.out.println(“La suma en “ + thread.
suma += nums[i]; getName()
System.out.println(“La suma en el for + “ es “ + suma);
para “ System.out.println(thread.getName() + “
+ Thread.currentThread(). TERMINANDO”);
getName() + “ es “ + suma); }
try { }
Thread.sleep(10);
} catch (InterruptedException exc) {
System.out.println(exc.
getMessage());
}
}
return suma;
}
}
class MiThread implements Runnable {
Thread thread;
static SumarArray sa = new SumarArray();
int numeros[]; int suma;
MiThread(String nombre, int numeros[]) {
thread = new Thread(this, nombre);
this.numeros = numeros;
thread.start();
}
Multitarea en Java | TELEFÓNICA / 16

En vez de sincronizar todo un método como en el ejemplo anterior, En el ejemplo anterior, se quitaría synchronized de la definición del
se pueden sincronizar el bloque de código en el que se invoca al método sumarArray y se añadiría el bloque sincronizado para el
método. Esto tiene que ser así obligatoriamente, si el método a acceso al array de números en la llamada a la función.
utilizar es de una clase de una librería de terceros.

El formato de esta utilización es:

public void run() {


synchronized(<referencia_objeto_a_bloquear>{ int suma;
//sentencias que invocan a metodo que accede System.out.println(thread.getName() + “
EMPEZANDO”);
//a objeto declarado entre los paréntesis synchronized(numeros){
} suma = sa.sumarArray(numeros);
}
System.out.println(“La suma en “ +
thread.getName() + “ es “ + suma);
System.out.println(thread.getName() + “
TERMINANDO”);
}
Multitarea en Java | TELEFÓNICA / 17

6. Comunicación de subprocesos:
notify, notifyAll y wait
Cuando un subproceso intenta acceder a un recurso y no puede conseguirlo, puede ponerse a la espera,
hasta que desde otro subproceso se le notifique que dicho recurso esta liberado. Por ejemplo, un
subproceso intenta añadir un elemento a una colección y está llena, puede este subproceso quedarse
en “WAITING” hasta que desde otro proceso le notifiquen que ya puede añadir el elemento.

Esta comunicación entre subprocesos se realiza con las funciones • notify(), saca de “WAITING” a uno de los subprocesos que estén
de la clase Object: en dicho estado y lo pasa a “RUNNABLE”. Su forma es:
• wait(), pone en “WAITING” al subproceso que invoca la función,
hasta que otro invoque a notify o notifyAll. Sus formas son: public final void notify()
public final void wait() throws InterruptedException
• notifyAll(), saca de “WAITING” a todos los subprocesos que
También se puede usar con estas dos formas, en las que se
estuvieran en este estado y los pasa “RUNNABLE”
espera a que otro invoque notify o notifyAll o pase el tiempo
especificado.

publicfinalvoidwait(longtimeout)throwsInterruptedException

public final void wait(long timeout, int nanos) throws


InterruptedException
Multitarea en Java | TELEFÓNICA / 18

7. Suspender, reanudar y detener subprocesos


Antes de Java 2 para suspender, reanudar y detener subprocesos se utilizaban las funciones de la clase
Thread:
• final void suspend()
• final void resume()
• final void stop()

El método suspend y el método stop causaban problemas, no En el ejemplo siguiente se muestra una posible forma de realizarlo.
funcionaba adecuadamente, y se decidió ponerlos “decrepated”, el
método resume como complementario a suspend pasó también a
este estado.

Sin utilizar estas funciones, estas operaciones se pueden realizar class MiThread implements Runnable {
con comprobaciones periódicas en el método run sobre si tiene que Thread thread;
suspender, reanudar o parar su propia ejecución. Se suelen utilizar boolean suspendido;
dos variables, una para suspender y reanudar, la otra para parar. boolean parado;

MiThread(String nombre) {
thread = new Thread(this, nombre);
suspendido = false;
parado = false;
thread.start();
}
Multitarea en Java | TELEFÓNICA / 19

Las funciones en el subproceso que actualizan los valores de las


variables suspendido y parado para que este pueda ser suspendido,
public void run() { reanudado o parado, son las que se muestran a continuación.
System.out.println(thread.getName() + “
ARRANCANDO”);
try {
for (int i = 1; i < 1000; i++) { synchronized void stop() {
System.out.print(i + “ “); parado = true;
if ((i % 10) == 0) { suspendido = false;
System.out.println(); notify();
Thread.sleep(400); }
}
//Bucle en run que hace las comprobaciones periódicas synchronized void suspend() {
//Sincronizar para acceder a suspendido y parado suspendido = true;
synchronized (this) { }
while (suspendido) {
wait(); synchronized void resume() {
} suspendido = false;
if (parado) notify();
break; }
} }
}
} catch (InterruptedException exc) { La funcionalidad suspender lleva al estado “WAITING”, la
System.out.println(thread.getName() funcionalidad reanudar lleva del estado “WAITING” al estado
+ “ INTERRUMPIDO”); “RUNNABLE” y la funcionalidad parar lleva al estado “TERMINATED”.
}
System.out.println(thread.getName() + “
FINALIZADO”);
}

También podría gustarte