⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 java14.htm

📁 E-books about Java Programing in Spanish
💻 HTM
字号:
<HTML>
<HEAD>

<META NAME="GENERATOR" CONTENT="Internet Assistant for Microsoft Word 2.0z">
<TITLE>Untitled</TITLE>
</HEAD>
<BODY background=/iconos/1.gif  TEXT=000000 LINK=FF0000 VLINK=A62A2A>

<H1>Java en hebras<BR>
</H1>
<P>
La clase anterior usamos, en el &uacute;ltimo ejemplo, un concepto
al que vamos a dedicar ahora nuestra atenci&oacute;n: los <I>threads</I>.
<P>
La traducci&oacute;n literal de <I>thread</I> es hilo o hebra,
y se utiliza tambi&eacute;n para referirse al hilo de un discurso.
El concepto de threads en los ambientes y sistemas operativos
es un poco complejo de explicar pero sencillo de entender: independientemente
del sistema elegido, puede pensarse que un thread es algo as&iacute;
como el lugar de ejecuci&oacute;n de un programa.
<P>
En la mayor&iacute;a de los programas que hemos visto, hemos usado
un solo thread; es decir que un programa comienza y su ejecuci&oacute;n
sigue un camino &uacute;nico: como un mon&oacute;logo.
<P>
Java es multithreading. Esto significa algo as&iacute; como que
tiene capacidad de di&aacute;logo, y m&aacute;s a&uacute;n: puede
ejecutar muchos threads en paralelo, como si trat&aacute;ramos
de una conversaci&oacute;n m&uacute;ltiple y simult&aacute;nea.
<P>
No confundir aqu&iacute; multithreading con la capacidad de ejecutar
varios programas a la vez. Esta es una posibilidad, pero tambi&eacute;n
un mismo programa puede utilizar varios threads (&quot;caminos
de ejecuci&oacute;n&quot;?) simult&aacute;neamente.
<P>
Esto, por supuesto, depende fundamentalmente de la capacidad del
sistema operativo para soportar multithreading, y por esto Java
no puede ejecutarse (al menos en forma completa) en sistemas que
no lo soporten.
<P>
El uso de threads nos permite, por ejemplo, ejecutar simult&aacute;neamente
varios programas que interact&uacute;en entre ellos; o, tambi&eacute;n,
que un programa, mientras por ejemplo actualiza la pantalla, simult&aacute;neamente
realice una serie de c&aacute;lculos sin tener que hacer esperar
el usuario.
<P>
Una forma sencilla de verlo es imaginar que tenemos un grupo de
microprocesadores que pueden ejecutar, cada uno, un solo thread;
y nosotros asignamos programas (o partes de programas) a cada
uno de ellos. Adem&aacute;s, podemos imaginar que esos microprocesadores
comparten una memoria com&uacute;n y recursos comunes, de lo que
surgir&aacute; una serie de problemas importantes a tener en cuenta
cuando se usan <I>threads</I>.
<H2>Los pasos b&aacute;sicos</H2>
<P>
Hay tres cosas a tener en cuenta para usar threads en un programa:
<UL>
<LI>La clase que queremos asignar a un thread debe implementar
la interface <I>Runnable</I>.
<LI>Debemos crear una variable (instancia) del tipo <I>Thread</I>,
que nos permitir&aacute;n acceder y manejar el thread. En los
applets, en el m&eacute;todo <I>start()</I> simplemente crearemos
el thread (y, posiblemente, lo pondremos a ejecutar)
<LI>Y por &uacute;ltimo tenemos que crear un m&eacute;todo run()
que es el que ejecuta el c&oacute;digo del programa propiamente
dicho.
</UL>
<P>
La interface Runnable, simplemente definida como:
<PRE>
<FONT SIZE=2>public  interface  java.lang.Runnable
{
        // Methods
    public abstract void run();
}</FONT>
</PRE>
<P>
le asegura al compilador que nuestra clase (la que utilizar&aacute;
el thread para ejecutarse) dispone de m&eacute;todo <I>run()</I>.
<P>
Vamos a ver un par de ejemplos, primero una aplicaci&oacute;n
standalone y luego un applet.
<H2>Reuni&oacute;n de amigos</H2>
<P>
El siguiente ejemplo (Ejemplo19.java) usa threads para activar
simult&aacute;neamente tres objetos de la misma clase, que comparten
los recursos del procesador pele&aacute;ndose para escribir a
la pantalla.<BR>
<PRE>
<FONT SIZE=2>class Ejemplo19 {

	public static void main(String argv[])
	throws InterruptedException {
		Thread Juan = new Thread (new Amigo(&quot;Juan&quot;));
		Thread Luis = new Thread (new Amigo(&quot;Luis&quot;));
		Thread Nora = new Thread (new Amigo(&quot;Nora&quot;));
		Juan.start();
		Luis.start();
		Nora.start();
		Juan.join();
		Luis.join();
		Nora.join();
	}

}

class Amigo implements Runnable {

	String mensaje;

	public Amigo(String nombre) {
		mensaje = &quot;Hola, soy &quot;+nombre+&quot; y este es mi mensaje &quot;;
	}

	public void run() {
		for (int i=1; i&lt;6; i++) {
			String msg = mensaje+i;
			System.out.println(msg);
		}
	}

}<BR>
</FONT>
</PRE>
<P>
Como siempre, compilarlo con <I>javac Ejemplo19.java</I> y ejecutarlo
con <I>java Ejemplo19</I>.
<P>
En un sistema operativo <I>preemptivo</I>, la salida ser&aacute;
m&aacute;s o menos as&iacute;:
<PRE>
<FONT SIZE=2>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.<BR>
</FONT>
</PRE>
<P>
Qu&eacute; significa que un sistema operativo es preemptivo? Casos
t&iacute;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 <I>no preemptivo</I>, el
procesador no se libera hasta que no termina con el thread actual,
y por lo tanto la salida ser&iacute;a as&iacute;:
<PRE>
<FONT SIZE=2>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.<BR>
</FONT>
</PRE>
<P>
Si ustedes est&aacute;n utilizando un sistema operativo no preemptivo,
deben expl&iacute;citamente indicarle al procesador c&uacute;ando
puede ejecutar (<I>dar paso</I>) a otra tarea; para eso simplemente
modifiquen el m&eacute;todo <I>run()</I>:
<PRE>
<FONT SIZE=2>	public void run() {
		for (int i=1; i&lt;6; i++) {
			String msg = mensaje+i;
			System.out.println(msg);
<B>			Thread.yield();
</B>		}
	}<BR>
</FONT>
</PRE>
<P>
En este ejemplo, tanto en sistemas preemptivos como no preemptivos
la salida ser&aacute;:
<PRE>
<FONT SIZE=2>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.<BR>
</FONT>
</PRE>
<P>
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 <I>yield()</I>, para sistemas
preemptivos: el procesador reparte su trabajo en forma (aparentemente)
impredecible, por eso el orden de los mensajes no ser&aacute;
el mismo en cualquier m&aacute;quina o sistema operativo.
<P>
Ya lo vimos funcionar, pero ser&iacute;a bueno que lo entendamos!
Por eso, vamos paso a paso.
<H2>Creando Threads</H2>
<P>
<I>Thread</I> es una clase b&aacute;sica en Java, que implementa
la interface <I>Runnable</I> y dispone de unos cuantos m&eacute;todos
por defecto. Lo importante a tener en cuenta que, para usar Threads,
debemos crearlas como instancias y ponerlas a &quot;andar&quot;:
<BR>
<PRE>
<FONT SIZE=2>		Thread Juan = new Thread (new Amigo(&quot;Juan&quot;));
		..............
		Juan.start();
		..............
		Juan.join();
</FONT>
</PRE>
<P>
Un thread tiene cuatro estados posibles:
<P>
<B>creado</B>: ha sido creado mediante <I>new()</I>, pero no se
ha puesto en marcha todav&iacute;a.
<P>
<B>activo</B>: est&aacute; en ejecuci&oacute;n, ya sea porque
arranc&oacute; con <I>start()</I> o fue &quot;despertado&quot;
con <I>resume()</I>.
<P>
<B>dormido</B>: ha sido suspendida su ejecuci&oacute;n moment&aacute;neamente
mediante <I>wait()</I>, <I>sleep()</I> o <I>suspend()</I>.
<P>
<B>muerto</B>: se ha detenido definitivamente, ya sea porque se
termin&oacute; el programa o mediante el llamado a <I>stop()</I>.
<P>
En este ejemplo hemos creado un thread asign&aacute;ndole simult&aacute;neamente
un objeto que lo utiliza (<FONT FACE="Arial">new Amigo(&quot;Juan&quot;)</FONT>),
y seguidamente lo hemos activado, llamando al m&eacute;todo <FONT FACE="Arial">start()</FONT>.
Este m&eacute;todo se encarga de inicializar el thread y, finalmente,
llamar al m&eacute;todo <FONT FACE="Arial">run()</FONT> que hemos
implementado.
<P>
De este modo, todo ocurre como si los m&eacute;todos <FONT FACE="Arial">run()</FONT>
de cada objeto se ejecutaran en paralelo, concurrentemente. La
forma de manejar esto depende del sistema operativo.
<P>
El m&eacute;todo <FONT FACE="Arial">join()</FONT> que llamamos
al final hace que el programa principal espere hasta que este
thread est&eacute; &quot;muerto&quot; (finalizada su ejecuci&oacute;n).
Este m&eacute;todo puede disparar la excepci&oacute;n InterruptedException,
por lo que lo hemos tenido en cuenta en el encabezamiento de la
clase.
<P>
En nuestro ejemplo, simplemente a cada instancia de <FONT FACE="Arial">Amigo(...)</FONT>
que creamos la hemos ligado a un thread y puesto a andar. Corren
todas en paralelo hasta que mueren de muerte natural, y tambi&eacute;n
el programa principal acaba.
<P>
Cuando usamos <FONT FACE="Arial">Thread.yield()</FONT> (que en
rigor deber&iacute;a ser <I>Thread.currentThread().yield()</I>,
pero siendo algo de uso muy com&uacute;n los desarrolladores de
Java lo han simplificado), simplemente el thread actual le permite
al procesador dedicarse a otro (si es que hay alguno deseando
utilizar sus servicios).
<P>
La clase <FONT FACE="Arial">Amigo()</FONT> es muy simple y con
lo que hemos visto hasta ahora no creo que tengamos que explicar
nada m&aacute;s.
<H2>Y los applets...?</H2>
<P>
Tambi&eacute;n podemos usar estos conceptos en los applets. Veamos
un ejemplo para terminar la clase de hoy, muy similar al anterior,
donde tres contadores cuentan (en un sistema preemptivo) en forma
simult&aacute;nea. Recuerden crear una p&aacute;gina HTML con
el tag
<PRE>
<FONT SIZE=2>&lt;applet code=&quot;Ejemplo20.class&quot; width=300 height=100&gt;&lt;/applet&gt;</FONT>
</PRE>
<P>
para poder verlo en acci&oacute;n con el appletviewer o su browser
favorito (que desde ya supongo que soporta Java! ;-)
<P>
El programa es extremandamente sencillo, y pueden verlo en acci&oacute;n
si lo desean cargando via Internet la p&aacute;gina:
<P>
<FONT FACE="Arial">http://www.amarillas.com/rock/java/Ejemplo20.htm
<BR>
</FONT>
<PRE>
<FONT SIZE=2>//	Ejemplo de applet que usa multithreading
import java.awt.*;
import java.applet.*;

public class Ejemplo20 extends Applet {

	TextField tfa,tfb,tfc;

	public void init() {
		setLayout(new GridLayout(3,2));
		tfa = new TextField(&quot;0&quot;);
		tfb = new TextField(&quot;0&quot;);
		tfc = new TextField(&quot;0&quot;);
		add(new Label(&quot;Contador A&quot;));
		add(tfa);
		add(new Label(&quot;Contador B&quot;));
		add(tfb);
		add(new Label(&quot;Contador B&quot;));
		add(tfc);
	}

	public void start() {
		Thread A = new Thread (new Counter(tfa));
		Thread B = new Thread (new Counter(tfb));
		Thread C = new Thread (new Counter(tfc));
		A.start();
		B.start();
		C.start();
	}

}

class Counter implements Runnable {

	TextField texto;
	String s;

	public Counter(TextField txtf) {
		texto = txtf;
	}

	public void run() {
		for (int i=0; i&lt;1000; i++) {
			texto.setText(s.valueOf(i));
		}
	}

}

<BR>
</FONT>
</PRE>
<P>
Disculpen la demora, pero estaba muy ocupado! Nos vemos la pr&oacute;xima
clase.<BR>
<BR>
<P>
Jorge Bourdette
<P>
<A HREF="mailto:jpb@amarillas.com" >jpb@amarillas.com</A><BR>
<BR>
</BODY>
</HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -