El siguiente ejemplo (Ejemplo19.java) usa threads para activar simultáneamente tres objetos de la misma clase, que comparten los recursos del procesador peleándose para escribir a la pantalla.
class Ejemplo19 {
public static void main(String argv[])
throws InterruptedException {
Thread Juan = new Thread (new Amigo("Juan"));
Thread Luis = new Thread (new Amigo("Luis"));
Thread Nora = new Thread (new Amigo("Nora"));
Juan.start();
Luis.start();
Nora.start();
Juan.join();
Luis.join();
Nora.join();
}
}
class Amigo implements Runnable {
String mensaje;
public Amigo(String nombre) {
mensaje = "Hola, soy "+nombre+" y este es mi mensaje ";
}
public void run() {
for (int i=1; i<6; i++) {
String msg = mensaje+i;
System.out.println(msg);
}
}
}
Como siempre, compilarlo con
javac Ejemplo19.java y ejecutarlo con
java Ejemplo19.
En un sistema operativo
preemptivo, la salida será más o menos así:
Hola, soy Juan y este es mi mensaje 1
Hola, soy Juan y este es mi mensaje 2
Hola, soy Luis y este es mi mensaje 1
Hola, soy Luis y este es mi mensaje 2
Hola, soy Nora y este es mi mensaje 1
Hola, soy Nora y este es mi mensaje 2
Hola, soy Nora y este es mi mensaje 3
Hola, soy Juan y este es mi mensaje 3
...........etc.
Qué significa que un sistema operativo es preemptivo? Casos típicos son Unix o Windows 95: cada tarea utiliza una parte del tiempo del procesador, y luego lo libera para que puedan ejecutarse otras tareas (otros threads). Por eso se mezclan los mensajes de salida. Si el sistema operativo es
no preemptivo, el procesador no se libera hasta que no termina con el thread actual, y por lo tanto la salida sería así:
Hola, soy Juan y este es mi mensaje 1
Hola, soy Juan y este es mi mensaje 2
Hola, soy Juan y este es mi mensaje 3
Hola, soy Juan y este es mi mensaje 4
Hola, soy Juan y este es mi mensaje 5
Hola, soy Luis y este es mi mensaje 1
Hola, soy Luis y este es mi mensaje 2
...........etc.
Si ustedes están utilizando un sistema operativo no preemptivo, deben explícitamente indicarle al procesador cúando puede ejecutar (
dar paso) a otra tarea; para eso simplemente modifiquen el método
run():
public void run() {
for (int i=1; i<6; i++) {
String msg = mensaje+i;
System.out.println(msg);
Thread.yield();
}
}
En este ejemplo, tanto en sistemas preemptivos como no preemptivos la salida será:
Hola, soy Juan y este es mi mensaje 1
Hola, soy Luis y este es mi mensaje 1
Hola, soy Nora y este es mi mensaje 1
Hola, soy Juan y este es mi mensaje 2
Hola, soy Luis y este es mi mensaje 2
Hola, soy Nora y este es mi mensaje 2
Hola, soy Juan y este es mi mensaje 3
Hola, soy Luis y este es mi mensaje 3
...........etc.
Esto es porque en seguida de imprimir estamos liberando al procesador para que pase a otro thread (si hay alguno esperando). Noten la diferencia con el primer caso, sin usar
yield(), para sistemas preemptivos: el procesador reparte su trabajo en forma (aparentemente) impredecible, por eso el orden de los mensajes no será el mismo en cualquier máquina o sistema operativo.
Ya lo vimos funcionar, pero sería bueno que lo entendamos! Por eso, vamos paso a paso.