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