Multiprocesos en Java: Hilos(Threads) El flujo múltiple de ejecución de programas permite que se estén realizando diferentes tareas al mismo tiempo en un programa, es decir, que las tareas se ejecuten de forma paralela, para ello Java utiliza unos elementos llamados hilos (thread). Cada hilo realiza una tarea en específico, al tener varios hilos ejecutándose, se tendrán varias tareas corriendo en el mismo programa. Lo que permitirá que en el mismo programa se estén realizando diferentes actividades al mismo tiempo. En Java, así como en cualquier lenguaje de programación, la principal estructura de ejecución de instrucciones es la estructura secuencial, en la que cada comando, cada línea, cada instrucción se ejecuta una después de otra. El código se ejecuta de arriba hacia abajo y cada línea es ejecutada según el orden en que haya sido escrita por el programador. El diagrama de flujo siguiente lo ejemplifica: Sin embargo existen alternativas. Si vemos el diagrama de arriba.En ocasiones puede que el usuario necesite llevar a cabo 2 o más procesos a la vez. obtendremos el siguiente resultado: . podemos identificar 3 hilos: Proceso 1. Si intentamos utilizar una estructura secuencial para ejecutar 3 procesos. ya hemos dicho que esto no es posible de la forma como lo hemos presentado en el diagrama de flujo. Proceso 2 y Proceso 3. como lo vemos en este modelo: Esto es completamente IMPOSIBLE ya que el procesador de una computadora no es capaz de realizar estas funciones. Supongamos que queremos realizar 3 procesos al mismo tiempo. Pero. como los Hilos o Threads. Los threads son estructuras secuenciales que combinan las líneas de 2 o más procesos en un solo proceso. El proceso 3 se empezará a ejecutar cuando haya terminado el proceso 1 y 2. Con los hilos o threads.Existe una serie de inconvenientes con esto: el proceso 1 sólo se ejecutará cuando haya terminado el proceso 2. Si lo expresamos con un diagrama de flujo se vería de la siguiente forma: . podemos obtener una ejecución lo más cercana posible al modelo de los 3 hilos que presenté arriba. Los comandos en azul pertenecen al proceso 1. dando como resultado algo bastante parecido a aquel modelo que ya hemos dicho que no es posible obtener con los procesadores de nuestras computadoras. Puede que se inicie la ejecución con el proceso 2. luego el 1 y así sucesivamente. Mientras que los programas de flujo único pueden realizar su tarea ejecutando las subtareas secuencialmente. luego el 2. No siguen un orden específico. La forma como se ejecutan los procesos es completamente aleatoria. un programa multitarea permite que cada tarea comience y . luego el 3. los comandos en rojo son del proceso 2 y el rojo del proceso 3. Esto permite que los 3 vallan corriendo al mismo tiempo. que forma parte del paquete java.lang. Insertamos un JFrame y le colocamos un botón con el que iniciaremos la ejecución se los Threads. 2002). Los hilos de ejecución en Java están implementados en la clase thread. pero no es una entidad independiente sino que debe ejecutarse en el contexto de un programa (Joyanes. Vamos a Netbeans y creamos un proyecto llamado Threads. Este comportamiento presenta una mejor respuesta a la entrada en tiempo real. un flujo de ejecución y un fin definidos. Cada hilo (thread) tiene un principio. Veamos cómo funcionan los Threads con una aplicación en Java. .termine tan pronto como sea posible. Ahora vamos al código y declaramos 3 variables tipo Thread. . Ahora vamos a programar el botón que colocamos en el JFRame. Nos aparecerá la opción “Implement all abstract methods”.swing.JFrame { para corregir el error.swing.JFrame implements Runnable{ . Dentro del código del botón iniciaremos los threads. quedara de la siguiente manera: public class ThreadsG extends javax. Lo corregimos dando clic en el ícono de la izquierda en nuestra declaración de la clase public class ThreadsG extends javax. Colocamos lo siguiente: Aquí Netbeans marca 3 errores con la inicialización de los threads. Esto se debe a que necesitamos implementar la interfaz Runnable en la Clase de nuestra JFrame. veremos una carrera de 3 procesos. } public void corredor3() { c3++. Serán del tipo entero y las inicializaremos en 0. } Estos métodos lo que harán es que le agregarán una unidad a cada una de las variables. } while (ct == hilo2) { corredor2().Para ver como se ejecutan los threads. } while (ct == hilo3) { . Allí colocamos lo siguiente: Thread ct = Thread.out.out. es decir. while (ct == hilo1) { corredor1(). System.println("Corredor 2: " + c2). c2 y c3.println("Corredor 1: " + c1). c1. c2 y c3. c1. Ahora nos dirigimos al final del programa. Luego introduciremos los siguientes métodos: public void corredor1() { c1++. System. } public void corredor2() { c2++. donde está el método public void run(). Primero declararemos 3 variables.currentThread(). imprime el valor de c1 en la parte inferior de Netbeans IDE. } / Esto funciona de la siguiente manera: La variable ct adoptará el valor del CurrenThread.out.out.corredor3().println("Corredor 3: " + c3). System. Mientras ese hilo funcióncorredor1 que que es se la esté ejecutando encargada de sea aumentar el hilo1. Se repite el mismo proceso para los otros 2 hilos. el hilo que se esté ejecutando en determinado instante. Lo hemos colocado uno debajo del otro. la se ejecutará variable c1. La la función System.println(“Corredor 1: ” + c1). Cuando ejecutamos el programa obtenemos lo siguiente: / . es decir. pero al ejecutar el programa y presionar el botón nos damos cuenta de que no es una secuencia. Lo que queremos darnos cuenta es como Java ejecuta el código. como una secuencia. Si detenemos el programa y empezamos una nueva ejecución obtendremos otro tipo de comportamiento. . Es probable que cada vez que ejecutemos el programa obtendremos resultados diferentes. el proceso 2 y 3 empezaron a ejecutarse a medida que el proceso 1 también se ejecutaba. sino que los 3 se ejecutarán en manera conjunta. es decir. el proceso inició ejecutándose con el método 1 (corredor1) pero al llegar a la línea 493 se volvió aleatorio. / Ahora el primer proceso en ejecutarse fue el proceso 1. luego el 3 y después el 2. Podemos observar que no es necesario esperar que el proceso 1 se termine de ejecutar para empezar con el 2 y el 3.Como podemos observar. el sistema se detiene cuando cualquiera de los “Corredores” llega a 500 para este ejemplo.Al final le hice unas modificaciones al código para obtener los resultados en una interfaz gráfica utilizando jFrame. El código es el siguiente: /* * José Luis Rubio Padilla * Manejo de Hilos en JAVA * */ package threads. /** * . swing. Thread hilo3. //Estos metodos incrementan la variable en uno. texto3="". se ejectaran en hilos diferentes public void corredor1() { c1++. c3=0. //Inicializa las cariables que se utilizaran para ejemplificar los hilos String texto1="". } .* @author jlrubio */ public class ThreadsG extends javax. } /** * Creates new form ThreadsG */ public ThreadsG() { initComponents(). texto2="". int c1=0. c2=0. Thread hilo1. } public void corredor2() { c2++. } public void corredor3() { c3++.JFrame implements Runnable{ //Estas variables sirven para dar nombre a lo hilos y //se imprimirán cada vez que los hilos estén en ejecución. Thread hilo2. jTextArea1. jTextArea1 = new javax.GroupLayout layout = new javax. getContentPane().WindowConstants.JScrollPane().addGroup(layout.awt.GroupLayout.JButton().swing.swing.ActionEvent evt) { jButton1ActionPerformed(evt).Alignment.event. jTextArea1.ActionListener() { public void actionPerformed(java.event.createParallelGroup(javax. jButton1.swing.setText("Ejecutar hilos"). jScrollPane1.awt. jScrollPane1 = new javax.addActionListener(new java.swing. jButton1. setDefaultCloseOperation(javax.swing. } }).setColumns(20). javax.setRows(5).setViewportView(jTextArea1).createSequentialGroup() ./** */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code"> private void initComponents() { jButton1 = new javax.setHorizontalGroup( layout. layout.JTextArea().LEADING) .setLayout(layout).swing.GroupLayout(getContentPane()).EXIT_ON_CLOSE).swing. hilo3 = new Thread(this).addGap(18. .addGroup(layout. 422. javax.GroupLayout.start(). pack().ActionEvent evt) { // TODO add your handling code here: hilo1 = new Thread(this). Short.addGroup(layout.LEA DING) .swing.addContainerGap() .MAX_VALUE) . hilo2.DEFAULT_SIZE.PREFERRED_SIZE. javax. }// </editor-fold> private void jButton1ActionPerformed(java.DEFAULT_SIZE.createParallelGroup(javax.PREFERRED_SIZE)) . javax.addContainerGap()) ).swing. 18.swing.Alignment.MAX_VALUE)) ).addComponent(jButton1) . 18) .Alignment.swing.. layout.GroupLayout.GroupLayout. hilo2 = new Thread(this).addComponent(jScrollPane1.GroupLayout. Short.GroupLayout. 312.addComponent(jButton1) .addContainerGap() .start(). hilo1.createSequentialGroup() .setVerticalGroup( layout.swing.createParallelGroup(javax.addComponent(jScrollPane1.LEADING) .GroupLayout.awt.swing.event.addContainerGap(javax. getLogger(ThreadsG.swing.util.getName())) { javax. } } } catch (ClassNotFoundException ex) { java.hilo3.getName()).start().getName()).SEVERE.class. * For details see http://download.util.setLookAndFeel(info.SEVERE. stay with the default look and feel.util.log(java. null. } /** * @param args the command line arguments */ public static void main(String args[]) { /* Set the Nimbus look and feel */ //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) "> /* If Nimbus (introduced in Java SE 6) is not available. ex).swing. null. } catch (InstantiationException ex) { java.UIManager.LookAndFeelInfo info : javax.swing.Logger.logging.log(java.class.Level. break.UIManager.Level.loggi ng.html */ try { for (javax.logging.util.UIManager.oracle.equals(info. } catch (IllegalAccessException ex) { .getInstalledLookAndFeels()) { if ("Nimbus".loggi ng. ex).getClassName()).Logger.getLogger(ThreadsG.com/javase/tutorial/uiswing/lookandfeel/plaf. loggi ng.log(java. while (ct == hilo1) { corredor1(). ex).logging.SEVERE.invokeLater(new Runnable() { public void run() { new ThreadsG().do not modify private javax. } //</editor-fold> /* Create and display the form */ java.util.swing. } catch (javax.Level.Logger.log(java.Logger. null. ex). } // Variables declaration .swing. private javax. texto1=texto1 + "Corredor 1: " + c1 + "\n".JScrollPane jScrollPane1.class.swing.getLogger(ThreadsG.util.logging.SEVERE.Level.java.getLogger(ThreadsG.getName()).awt. null.getName()). } }).util.JButton jButton1. private javax.EventQueue. .util.JTextArea jTextArea1.setVisible(true). // End of variables declaration @Override public void run() { Thread ct = Thread.UnsupportedLookAndFeelException ex) { java.currentThread().swing.loggi ng.class. this. choose Tools | Templates.jTextArea System. texto1=texto1 + "Corredor 2: " + c2 + "\n".this. if (c2==500) break. //se colcoca el resultado en el contro. .").jTextArea System.jTextArea1.setText(texto1).println("Corredor 1: " + c1).println("Corredor 3: " + c3).jTextArea1.setText(texto1). //Al llegar a 500 ejecuciones detengo la ejecución para observar el resultado } while (ct == hilo3) { corredor3(). if (c1==500) break.setText(texto1). //To change body of generated methods.out. //se colcoca el resultado en el contro.out. if (c3==500) break. //se colcoca el resultado en el contro.jTextArea System.out. this. //Al llegar a 500 ejecuciones detengo la ejecución para observar el resultado } while (ct == hilo2) { corredor2().jTextArea1.println("Corredor 2: " + c2). texto1=texto1 + "Corredor 3: " + c3 + "\n". //Al llegar a 500 ejecuciones detengo la ejecución para observar el resultado } throw new UnsupportedOperationException("Not supported yet. } } Conclusiones: Con los hilos de ejecución podemos terminar mucho más rápido nuestra aplicación. sobre todo cuando son grandes volúmenes de datos o cálculos que se tienen que procesar. .