Multiprocesamiento en Java: ¡Dale caña a tu procesador!

Multiprocesamiento, como reza la Wikipedia, se refiere a la ejecución de varios procesos de manera concurrente, es decir, a la vez. Con los nuevos procesadores que cada vez nos traen más núcleos, he visto que ésto viene a ser más importante. Con Java el multiprocesamiento para aprovechar los núcleos de uno o varios procesadores viene gestionado con la máquina virtual de Java. Es decir, sólo tendremos que preocuparnos de hacer el programa de manera que se puedan ejecutar ‘a trozos’, poner cada tarea en un hilo de ejecución y luego la máquina virtual se encargará de gestionarlo todo.

Ésto es lo mismo que viene ocurriendo con los Sistemas Operativos (SO). Tenemos muchos procesos que se ejecutan desde que arrancamos el ordenador, y el SO se encarga de gestionar qué se ejecuta en cada momento. De igual manera nosotros en Java podemos gestionar qué se ejecuta o que se queda esperando, también podemos decirle a todas las tareas que se ejecuten a la vez simplemente sin esperar unas a otras ni nada parecido. Ésto es lo que vamos a ver con el ejemplo sencillo de a continuación, donde se van a crear dos tareas, a y b, y se van a ejecutar concurrentemente.


Tenemos éste código:

package variado;
 
 // ESTE EL PROGRAMA PRINCIPAL ----
 public class manejadorDeHilos {
  public static void main(String[] args) {
  unaTareaEnUnHilo a, b;
  a = new unaTareaEnUnHilo();
  b = new unaTareaEnUnHilo();
 
  a.start();
  b.start();
  }
 }
 
 // FIN DEL PROGRAMA PRINCIPAL ----
 
 // Éste es un objeto que representa
 // una tarea que se ejecuta en un hilo
 class unaTareaEnUnHilo extends Thread {
  public void run() {
  for (int i = 0; i < 100; i++) {
  System.out.print(i + ", ");
  }
  }
 }
La clase manejadorDeHilos es una objeto sencillo que crea dos variables a y b, las dos del mismo tipo. El meollo del asunto está programado con la clase unaTareaEnUnHilo, que extiende de la clase Thread, la cual significa hilo en castellano. 
Tenemos entonces que hacer las tareas en una clase que extienda de Thread para que se ejecute en un hilo. Y a su vez tenemos que programar el método run(), que es el que se ejecuta cuando el hilo arranca. Las variables del tipo unaTareaEnUnHilo tienen un método propio de la clase Thread que es start(), con el cual le decimos que comience su ejecución, el cual lo que hace es simplemente ejecutar la función run() como en el ejemplo.
Lo copiamos y pegamos en un fichero llamado manejadorDeHilos.java en nuestro IDE favorito, lo ejecutamos, y a mi por ejemplo me escribe lo siguiente por la salida estándar:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 0, 1, 2, 3, 4, 5, 6, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 7, 8, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 83, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 91, 95, 92, 96, 93, 94, 95, 96, 97, 98, 99, 97, 98, 99, 
Vamos a ver qué ha pasado. ¿Porqué no se ha ejecutado la tarea a y luego la b? ¿porqué están desordenados los números?
Las dos tareas se han ejecutado a la vez, y cuando han podido han ido escribiendo el número por el que iban contando. Si ejecutamos varias veces el programa veremos que da resultados distintos.
En líneas generales ésto es lo mínimo necesario para empezar con los hilos de Java.  Luego podemos interrumpir con la función interrupt() o continuar la ejecución de un hilo con resume(). También podemos poner a dormir un hilo con sleep(). Para jugar un poco con los hilos podríamos crear un vector de hilos y que el hilo 1 hiciera dormir al 2 y cuando haya terminado de ejecutar su tarea que corra el 2. Y de paso un tercer hilo que se ejecute contínuamente.
Entonces, ¿para qué todo ésto de los hilos? Voy a seguir con el mismo ejemplo, se me ha ocurrido cambiar la tarea unaTareaEnUnHilo de la manera siguiente:
class unaTareaEnUnHilo extends Thread {
  public void run() {
  for (int i = 0; i < 100000000; i++) {
  for (int j = 0; j < 100000000; j++) {
  for (int k = 0; k < 100000000; k++) {
  for (int l = 0; l < 100000000; l++) {
 
  }
  }
  }
  }
  }
 }
Ahora dirás, ¡ostras! ¡cuántos bucles! Ahora va a tardar mucho cada hilo, y esta vez sí que se va a notar si se han usado los hilos o no en el tiempo total que va a tardar, aunque tal vez tarde demasiado y haya que pararlo antes… Entonces podemos ver cómo se nota la ejecución con el visor de los núcleos del PC. Al ejecutar el programa con las modificaciones, el administrador de tareas, muestra lo siguiente de mi procesador:

 

 

Se puede ver claramente que los núcleos de mi procesador son 4, y de los cuáles el segundo y tercero son los que están ejecutando las tareas a y b. Y mi procesador va al 50% aproximadamente. Si pusiéramos dos tareas más con hilos subiría al 100% y aprovecharíamos el procesador bien. Podemos modificar el ejemplo anterior cambiando sólo el manejadorDeHilos para verlo al 100%:
public class manejadorDeHilos {
  public static void main(String[] args) {
  unaTareaEnUnHilo a, b, c, d;
  a = new unaTareaEnUnHilo();
  b = new unaTareaEnUnHilo();
  c = new unaTareaEnUnHilo();
  d = new unaTareaEnUnHilo();
 
  a.start();
  b.start();
  c.start();
  d.start();
  }
 }
Si no hubiera utilizado los hilos, para ejecutar las dos tareas, el procesador hubiera ido al 25% más o menos y hubiera tardado bastante más en terminar. Se hubieran ejecutado primero una, luego la otra, y los números hubieran salido todos ordenados por la pantalla. ¿Qué pasa entonces cuando tengo muchas tareas? no sólo dos o cuatro. Pues ya es otro tema, podemos hacer un vector de tareas, una cola de tareas, una lista o lo que sea que se nos pueda ocurrir. Imaginemos pues qué haríamos si quisiéramos hacer unas 3000 tareas, mejor si está programado cada una en un hilo, y se lanzan todos los hilos, seguro que el procesador terminaría antes y se pondría a echar humo.

Así que pues, a darle caña a nuestro procesador xD

Un saludo.

Compartir..

Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

diecisiete − 12 =