You are on page 1of 36

Antecedentes

1. Manejar sentencias de control de flujo en lenguaje de Java.


2. Identificar y relacionar varias clases en la programación orientada a objetos
empleando la teoría de diseño de jerarquía de clases
3. Haber utilizado archivos en el almacenamiento de datos
4. Manejar los conceptos de proceso y multitareas
Introducción
En Java, para lograr la comunicación entre el programa y la información, ya sea de entrada
o salida, se hace mediante un flujo, que funge como el intermediario entre el programa y los
datos.
En la práctica de programación orientada a objetos con manejo de excepciones, se observó
que para hacer la lectura de datos desde el teclado, se tiene que generar un flujo de entrada,
es decir, una operación InputStreamReader; y el parámetro que recibe es el origen de los
datos, en ese caso System.in, pero para realizar la lectura de información contenida en
archivos o ficheros, se necesita generar un objeto de tipo File, igual que como se crea un
apuntador FILE en C.
File f = new File(nombreArchivo);
Una vez creado el apuntador, se necesita generar el flujo de datos desde un archivo, es decir,
crear un objeto de tipo FileInputStream, que recibe como parámetro el objeto de tipo File.
FileInputStream fis = new FileInputStream(f);
Con esto, ya se puede crear el InputStreamReader, que permitirá leer los datos que se
tengan en un archivo; y el BufferedReader que hará la lectura de los mismos.
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader br = new BufferedReader(isr);
Ya con estas cuatro líneas se puede hacer la lectura de un archivo.

PRÁCTICA
PROGRAMACIÓN ORIENTADA A OBJETOS (ARCHIVOS E HILOS)

Elaborar un programa que lea la información contenida en un archivo de texto plano.


import java.io.*;
public class LeeArchivo{
File f;
FileInputStream fis;
InputStreamReader isr;
BufferedReader br;
String linea;
public static void main(String args[]){
try{
LeeArchivo la = new LeeArchivo();
//Se crea un objeto de tipo File
la.f = new File(args[0]);
//Se genera el flujo de entrada desde archivo
la.fis = new FileInputStream(la.f);
//Se crea el flujo de lectura
la.isr = new InputStreamReader(la.fis);
//Se crea el objeto que permitirá la lectura
la.br = new BufferedReader(la.isr);
//Se hará la lectura hasta que encuentre una línea nula
while((la.linea=la.br.readLine())!=null){
System.out.println(la.linea);
}
//Se cierran todos los flujos
la.br.close();
la.isr.close();
la.fis.close();
}
catch(IOException ioe){
System.out.println(ioe.getMessage());
}
}
}
Debido a que todos los flujos de entrada y salida generan una excepción de entrada/salida,
es necesario agregar una secuencia de try-catch.
Escritura en archivos
Ahora, para hacer la escritura en archivos se debe generar, de igual forma que para la
lectura, flujos de entrada o salida. En este caso, en lugar de utilizar FileInputStream,
debemos generar un flujo de salida, es decir FileOutputStream.
FileOutputStream fos = FileOutputStream(f);

Debido a que ahora la impresión es en un archivo, se deberá utilizar el comando:


PrintStream ps = PrintStream(fos);
Ejemplo 2
Elaborar un programa que escriba en archivo una línea que se escriba desde línea de
comando.
import java.io.*;
public class EscribeArchivo{
String cadena;
File f;
FileOutputStream fos;
PrintStream ps;
public static void main(String args[]){
try{
EscribeArchivo ea = new EscribeArchivo();
//Se obtiene la cadena que se escribirá en el archivo
ea.cadena = args[0];
//Se crea un objeto de tipo File
ea.f = new File(args[1]);
//Se genera el flujo de salida hacia el archivo
ea.fos = new FileOutputStream(ea.f);
//Se genera el escritor del flujo
ea.ps = new PrintStream(ea.fos);
//Se escribe la línea dentro del archivo
ea.ps.println(ea.cadena);
//Se cierran flujos
ea.ps.close();
ea.fos.close();
}
catch(IOException ioe){
}
catch(ArrayIndexOutOfBoundsException aioobe){
System.out.println("ERROR!!!");
System.out.println("Sintaxis: java EscribeArchivo
\"cadena\" archivo");
}
}
}

Hilos

Cuando se genera un proceso, se crea un hilo primario, que está asociado a un bloque de
instrucciones, un conjunto de registros y una pila. Este hilo, puede crear más hilos si es
necesario; a estos hilos se les denomina “procesos ligeros” ya que comparten ciertos
recursos con el proceso primario que los creó.

PRÁCTICA
PROGRAMACIÓN ORIENTADA A OBJETOS (ARCHIVOS E HILOS)

Pero, ¿para qué se necesitan varios hilos? Cuando se hace una aplicación robusta en el que
tenga que hacer varias acciones al mismo tiempo, en lugar de crear un proceso completo, es
más conveniente crear un hilo que pueda llevar a cabo las acciones correspondientes de una
forma rápida y eficaz. Por ejemplo, si se tiene un sistema que está en red, para que
múltiples usuarios tengan acceso, si se generara un proceso por cada usuario, saldría
bastante caro, hablando de recursos máquina, pero si se genera un hilo, para que haga una
consulta, o una actualización de un dato, las acciones se realizan rápidamente.
Hay varios estados por los que pasa un hilo, y son:
Preparado.- Cuando se genera un hilo nuevo y está listo para ejecutarse, o cuando
ha sido desbloqueado.
En ejecución.- Cuando está haciendo uso de los recurso de la CPU.
Bloqueado.- Cuando está en espera de que se elimine el bloqueo.
o Dormido.- Cuando se bloquea por un cierto tiempo, después del cual
despierta, y pasa a preparado.
o En espera.- Cuando está esperando a que ocurra algo, recibe un mensaje y
pasa a preparado.
Muerto.- Cuando ha terminado de ejecutarse.
En Java, cuando se trabaja con hilos, se debe indicar que la clase con la que se está
trabajando es una subclase de la clase Thread, es decir, que se heredarán todas las
propiedades que contiene la clase Thread.
Ejemplo 3
Elabore un programa que genere 6 hilos.
public class GeneraHilo extends Thread{
//Rutina que se ejecuta cuando se le da start() a un hilo
public void run(){
System.out.println("Esta es una instancia de nuestra clase: "
+this.getName());
}
public static void main(String args[]){
//Se generan 6 hilos
GeneraHilo gh1 = new GeneraHilo();
GeneraHilo gh2 = new GeneraHilo();
GeneraHilo gh3 = new GeneraHilo();
GeneraHilo gh4 = new GeneraHilo();
GeneraHilo gh5 = new GeneraHilo();
GeneraHilo gh6 = new GeneraHilo();
//Se les asigna nombre
gh1.setName("Hilo1");
gh2.setName("Hilo2");
gh3.setName("Hilo3");
gh4.setName("Hilo4");
gh5.setName("Hilo5");
gh6.setName("Hilo6");

//Se "ejecutan" los hilos


gh1.start();
gh2.start();
gh3.start();
gh4.start();
gh5.start();
gh6.start();
System.out.println("Hilo Principal:"
+Thread.currentThread().getName());
}
}

EJERCICIOS PROPUESTOS
1. El programa del Ejemplo 1, tiene una falla cuando no se le pasan parámetros,
arréglelo utilizando un catch. Además, cuando se le da el nombre de un archivo no
existente aparece la leyenda
(El sistema no puede hallar el archivo especificado)
Modifique el programa de tal forma que se indique:
ERROR!!!
Archivo no válido, favor de verificar el nombre del archivo.
TIP: Utilice una excepción para la modificación de archivo no válido.
2. Modifique el programa del Ejemplo 2 de tal forma que ahora se escriba en archivo
todo lo que se escriba mientras está en ejecución el programa.
3. Modifique el programa anterior, para que también se pueda agregar información al
final del archivo que se indique.
4. Elabore un programa que lea información de un archivo, y lo escriba en otro.
5. Cuando se ejecuta varias veces seguidas el programa del Ejemplo 3, ¿qué pasa?
Ahora en el método run(), agregue la instrucción
sleep((long)Math.random()*2500), antes de la impresión del nombre del
hilo que se está ejecutando. Haga las modificaciones necesarias para que compile y
ejecute correctamente el programa. Si se ejecuta varias veces seguidas el programa,
¿Ahora, qué sucede?
Concepto de Hilos de Ejecución

Para solucionar este problema, los programadores han creado lo que se llaman "hilos de
ejecución" (Threads). Su razonamiento es que cada proceso es una colección de uno o más
"hilos". Todos los programas tienen al menos un hilo, que es en el caso de los programas de
Delphi (y de casi todos los lenguajes de Windows) el mismo hilo que procesa todos los
mensajes. Pero cualquier hilo puede crear otro "hilo" con un pedazo de código, y este hilo
podrá ejecutar al mismo tiempo que el programa, sin necesidad de interrumpirlo.

TODO: Hacer gráfica de hilos de ejecución.

Esto puede ser bastante complejo; ya que aunque Windows puede protegerlo de accesar
memoria que pertenece a otros procesos, no lo va a ayudar si varios hilos tratan de accesar
la misma memoria. Así que usted tiene que tener cuidado, cuando accesa las variables de
un hilo, de que el hilo no la esté utilizando, porque si no lo hace, los resultados pueden ser
impredecibles.

Una de las tareas más complicadas de un desarrollador


experto es la depuración de errores causados por hilos de
ejecución. Es por esto muy importante que usted
comprenda todos los conceptos aquí explicados
perfectamente bien. Los errores de hilos de ejecución no
siempre son evidentes, y pueden causar que los programas
se traben (sin dar mensajes de error) en circunstancias muy
diversas y por motivos que muchas veces no son obvios.

Comunicación Entre Hilos

Así que usted puede hacer que varios hilos de ejecución ejecuten simultáneamente en su
programa, pero no puede hacer que los hilos accesen memoria de otros hilos al mismo
tiempo... ¿Entonces, cómo le hacemos para comunicarnos?

El caso más común donde desearíamos comunicarnos con el hilo de ejecución principal
sería para escribir algo en la pantalla (tal vez aumentar el valor de un ProgressBar o escribir
en una etiqueta el estado actual de nuestro hilo). Para comunicarnos entre diversos hilos,
debemos detener todos los hilos en favor del hilo principal, y decirle a este hilo que
actualice la pantalla por nosotros. Este procedimiento se llama "sincronización".

Obviamente, es muy importante evitar que cualquier sincronización tome demasiado


tiempo, porque haría a nuestro programa sentirse lento en vez de ayudar.

Implementación de Hilos de Ejecución en Delphi


Delphi tiene un objeto específicamente para manejar hilos de ejecución, que es llamado,
adecuadamente, TThread. Este objeto es abstracto, lo cual quiere decir que no lo podemos
instanciar hasta que lo "heredemos" y creemos nuestro propio TThread. Pero lo que nos da
es los primitivos de creación de Hilos y sincronización para que no necesitemos llamar al
API de Windows.

¿Cómo le decimos a TThread qué código queremos ejecutar? TThread tiene un


procedimiento llamado Execute que usted debe implementar. Es en este procedimiento
donde usted puede escribir su código.

A continuación presento una pieza simplificada de código con las porciones indispensables
para que un hilo de ejecución funcione:

type

TBoxParser = class(TThread)
private
protected
procedure Execute; override;
procedure MostrarProgreso; override;
public
end;

implementation

procedure TBoxParser.Execute;
var
i : Integer;
begin

for i := 0 to MBox.MessageList.Count -1 do begin


FCurrentMessage := 'Reading '+MBox.MessageList.Items[i].MailFrom;
if Terminated then exit;
// Esto actualiza la forma evitando conflictos entre hilos.
Synchronize(MostrarProgreso);
end;

end;

procedure TBoxParser.MostrarProgreso;
begin

// Esto corre bajo el contexto del hilo principal.


mainform.StatusBar1.Panels[0].Text := FCurrentMessage;
mainform.ProgressBar1.Max := MboxMax;
mainform.ProgressBar1.Position := MBoxCurrent;

end;

Como podrá ver en el código, es responsabilidad de usted checar si el hilo ha sido


terminado desde afuera (alguien que llame TThread.Terminate) e interrumpir su proceso.
Además, si usted quiere actualizar la interfaz del usuario usted debe llamar Synchronize, ya
que todo lo que vive en la interfaz del usuario corre en el contexto del hilo principal.

Prioridad y Señales

Los hilos de ejecución pueden tener varios niveles prioridad. El hilo puede cambiar su
propia prioridad, pero debe usted tener en cuenta de que otros hilos en su programa (o el
sistema operativo mismo) puede cambiar su prioridad, así que procure no depender en la
prioridad.

Ya hemos visto que otros hilos de ejecución pueden pedir que terminemos el programa, y
eso lo debemos manejar nosotros mismos. Esta es una de las señales que el programa nos
puede enviar, pero también puede suspendernos y continuarnos (Suspend/Resume).
Siempre tenga esto en cuenta y programe defensivamente. Por ejemplo, si usted utiliza un
recurso en un loop, asegúrese de que el recurso exista dentro del loop. Esa clase de cosas.

Uso de Recursos

Los hilos de ejecución que usted implemente deben estar programados de tal manera que
"jueguen limpio" con los recursos. Esto quiere decir verificar que el recurso no esté en uso
por otra tarea.

Bases de Datos e Hilos de Ejecución

Uno de los recursos que debemos procurar no accesar en varios hilos al mismo tiempo son
las conexiones a bases de datos. El BDE permite multitarea pero no sobre la misma
conexión. Esto quiere que usted deberá:

1. Crear un TDatabase y TSession por cada hilo de ejecución


2. Utilizar algún otro método (de programación) que nos permita asegurarnos que la
base de datos nunca se compartirá.

En Delphi es más sencillo crear los hilos y asignarles un nuevo TDatabase y TSession a
cada uno.

En el siguiente fragmento de código, estoy creando algunos queries, y al hacer esto estoy
pidiendo la sesión y base de datos especificadas en el miembro "Database", que es un
TDatabase que yo inventé:

procedure TBoxParser.Execute;
var
i : Integer;
begin

qGente := TQuery.Create(Database.Owner);
qEncuestas := TQuery.Create(Database.Owner);
qGente.SessionName := Database.SessionName;
qGente.DatabaseName := Database.DatabaseName;
qEncuestas.SessionName := Database.SessionName;
qEncuestas.DatabaseName := Database.DatabaseName;
qGente.SQL.Add('SELECT * FROM People WHERE EMail = :Email');
qGente.RequestLive := True;
qGente.Params[0].DataType := ftString;
qEncuestas.SQL.Add('SELECT * FROM DelphiEncuestas WHERE EMail =
:Email');
qEncuestas.Params[0].DataType := ftString;
qEncuestas.RequestLive := True;

El código que crea este hilo esta creando la base de datos (cuya variable es DBThread) por
mí. Me conecta (para que el diálogo de Login/Password se ejecute desde el hilo principal),
y una vez que tenga conectada la base, asigna la variable "Database" del hilo a la
TDatabase a la que me conectó. De esta manera puedo estar seguro de que mi base de datos
está lista para acceso. Es responsabilidad del hilo principal no utilizar la base hasta que el
TThread Termine.

FParseThread := TBoxParser.Create(True);
dbThread.Connected := True;
TBoxParser(FParseThread).Database := dbThread;
FParseThread.Resume;

Nota: El Hilo se está creando con el parámetro "True", que


quiere decir que queremos que comience suspendido. Es
muy importante dar este parámetro, ya que si no lo
hacemos el procedimiento Execute comenzará de
inmediato, y no podremos definir los datos que queremos
procesar (en este caso, la base de datos que usaremos para
conectarnos). Para continuar el proceso una vez que hemos
definido todo lo que queramos, podemos llamar
"Resume".

Modelos de Diseño con Hilos de ejecución

Cuando diseñamos programas con varios hilos de ejecución que hagan tareas repetitivas,
usted debe estar consciente de el manejo los hilos de ejecución en los programas para
asegurarse de que su programa no se trabe por uso simultáneo de recursos o demasiados
hilos a la vez. Estas consideraciones nos hacen tener que decidir entre dos modelos de
diseño:

Hilo-por-Cliente (Thread Per Client)

Bajo este modelo, cada cliente que usted genera crea un nuevo hilo. Cuando el cliente se
desconecta (o el hilo termina su operación), el hilo se borra. Esto es fácil de programar. Por
ejemplo, el evento OnClick de un boton puede crear un TThread y ejecutarlo. Pero el
problema es que es fácil trabar el sistema si no tenemos cuidado (el usuario presionando el
boton mil veces a la vez). El manual del API de Windows nos recomienda no crear más de
16 hilos de ejecución secundarios para evitar inestabilidad.

Aunque es fácil de escribir, este modelo sólo funciona para unos cuantos hilos, y entre más
hilos sean necesarios, más importante es encontrar otra manera.

Colección de Hilos (Thread Pool)

En un Thread Pool, usted tiene un objeto que mantiene una lista de punteros a hilos de
ejecución que pueden estar "libres" u "ocupados". Esta colección corre desde el contexto
del hilo principal y el hilo principal utiliza la lista para pedir un nuevo hilo. La lista busca
entre todos los hilos uno que no esté ocupado. Si encuentra uno, lo proporciona. Si no, crea
uno nuevo, lo añade a la lista y lo proporciona, a menos que la lista tenga el Máximo de
hilos permitidos, que usted determina (en cuyo caso se crea el error "Servidor demasiado
ocupado").

Una vez que el hilo ha terminado la lista se actualiza marcando el hilo como "libre".

Este procedimiento es excelente para los usuarios que necesitan compartir recursos como
conexiones de red o conexiones a bases de datos. Estos sistemas son más difíciles de
escribir porque debemos crear la colección y mantener la lista, además de asegurarnos de
que el código existente nunca llame a los hilos por sí mismo (sino siempre use la lista).
Pero nos proporciona dos ventajas:

Primero, nos permite reutilizar hilos que no estén siendo usados, haciendo que nuestro
programa pueda dar servicio a más clientes y a la vez reduzca los requerimientos sobre el
sistema. Segundo, la complejidad se queda en el módulo de la colección, y mientras usted
sea disciplinado en su programación de objetos, cualquier error en su modelo de hilos de
ejecución probablemente será un error en la manera de implementar esta lista.
3. Programación concurrente multihilo

Introducción:

En sistemas operativos, un hilo de ejecución o subproceso es una


característica que permite a una aplicación realizar varias tareas a la vez
(concurrentemente). Los distintos hilos de ejecución comparten una serie de
recursos tales como el espacio de memoria, los archivos abiertos, situación de
autenticación, etc. Esta técnica permite simplificar el diseño de una aplicación que
debe llevar a cabo distintas funciones simultáneamente.

Un hilo es básicamente una tarea que puede ser ejecutada en paralelo con otra
tarea. Los hilos de ejecución que comparten los mismos recursos, sumados a
estos recursos, son en conjunto conocidos como un proceso. El hecho de que los
hilos de ejecución de un mismo proceso compartan los recursos hace que
cualquiera de estos hilos pueda modificar éstos. Cuando un hilo modifica un dato
en la memoria, los otros hilos acceden a ese dato modificado inmediatamente.

Lo que es propio de cada hilo es el contador de programa, la pila de ejecución y el


estado de la CPU (incluyendo el valor de los registros).

El proceso sigue en ejecución mientras al menos uno de sus hilos de ejecución


siga activo. Cuando el proceso finaliza, todos sus hilos de ejecución también han
terminado. Asimismo en el momento en el que todos los hilos de ejecución
finalizan, el proceso no existe más y todos sus recursos son liberados.

Algunos lenguajes de programación tienen características de diseño


expresamente creadas para permitir a los programadores lidiar con hilos de
ejecución (como Java o Delphi). Otros (la mayoría) desconocen la existencia de
hilos de ejecución y éstos deben ser creados mediante llamadas de biblioteca
especiales que dependen del sistema operativo en el que estos lenguajes están
siendo utilizados (como es el caso del C y del C++).
3.1 Concepto de Hilo

En sistemas operativos, un hilo de ejecución o subproceso es una


característica que permite a una aplicación realizar varias tareas a la vez
(concurrentemente). Los distintos hilos de ejecución comparten una serie de
recursos tales como el espacio de memoria, los archivos abiertos, situación de
autenticación, etc. Esta técnica permite simplificar el diseño de una aplicación que
debe llevar a cabo distintas funciones simultáneamente.

Un hilo es básicamente una tarea que puede ser ejecutada en paralelo con otra
tarea.

Los hilos de ejecución que comparten los mismos recursos, sumados a estos
recursos, son en conjunto conocidos como un proceso. El hecho de que los hilos
de ejecución de un mismo proceso compartan los recursos hace que cualquiera de
estos hilos pueda modificar éstos. Cuando un hilo modifica un dato en la memoria,
los otros hilos acceden a ese dato modificado inmediatamente.

Lo que es propio de cada hilo es el contador de programa, la pila de ejecución y el


estado de la CPU (incluyendo el valor de los registros).

El proceso sigue en ejecución mientras al menos uno de sus hilos de ejecución


siga activo. Cuando el proceso finaliza, todos sus hilos de ejecución también han
terminado. Asimismo en el momento en el que todos los hilos de ejecución
finalizan, el proceso no existe más y todos sus recursos son liberados.

Algunos lenguajes de programación tienen características de diseño


expresamente creadas para permitir a los programadores lidiar con hilos de
ejecución (como Java o Delphi). Otros (la mayoría) desconocen la existencia de
hilos de ejecución y éstos deben ser creados mediante llamadas de biblioteca
especiales que dependen del sistema operativo en el que estos lenguajes están
siendo utilizados (como es el caso del C y del C++).

Un ejemplo de la utilización de hilos es tener un hilo atento a la interfaz gráfica


(iconos, botones, ventanas), mientras otro hilo hace una larga operación
internamente. De esta manera el programa responde de manera más ágil a la
interacción con el usuario. También pueden ser utilizados por una aplicación
servidora para dar servicio a múltiples clientes.

Los hilos no pueden ejecutarse ellos solos; requieren la supervisión de un proceso


padre para correr.

Dentro de cada proceso hay varios hilos ejecutándose.


Por ejemplo, Word puede tener un hilo en background chequeando
automáticamente la gramática de lo que estoy escribiendo, mientras otro hilo
puede estar salvando automáticamente los cambios del documento en el que
estoy trabajando. Como Word, cada aplicación (proceso) puede correr varios hilos
los cuales están realizando diferentes tareas. Esto significa que los hilos están
siempre asociados con un proceso en particular.

Los hilos a menudo son conocidos o llamados procesos ligeros. Un hilo, en efecto,
es muy similar a un proceso pero con la diferencia de que un hilo siempre corre
dentro del contexto de otro programa. Por el contrario, los procesos mantienen su
propio espacio de direcciones y entorno de operaciones. Los hilos dependen de un
programa padre en lo que se refiere a recursos de ejecución. La siguiente figura
muestra le relación entre hilos y procesos.

Un programa de flujo único o mono-hilvanado (single-thread) utiliza un único flujo


de control (thread) para controlar su ejecución. Muchos programas no necesitan la
potencia o utilidad de múltiples flujos de control. Sin necesidad de especificar
explícitamente que se quiere un único flujo de control, muchos de los applets y
aplicaciones son de flujo único.

Por ejemplo, en nuestra aplicación estándar de saludo:


public class HolaMundo

static public void main( String args[] )

System.out.println( "Hola Mundo!" );

}
Aquí, cuando se llama a main(), la aplicación imprime el mensaje y termina. Esto
ocurre dentro de un único thread.

La clase Thread

Es la clase que encapsula todo el control necesario sobre los hilos de ejecución
(threads). Hay que distinguir claramente un objeto Thread de un hilo de ejecución
o thread. Esta distinción resulta complicada, aunque se puede simplificar si se
considera al objeto Thread como el panel de control de un hilo de ejecución
(thread). La clase Thread es la única forma de controlar el comportamiento de los
hilos y para ello se sirve de los métodos que se exponen en las secciones
siguientes.

Métodos de Clase

Estos son los métodos estáticos que deben llamarse de manera directa en la clase
Thread.

currentThread()

Este método devuelve el objeto thread que representa al hilo de ejecución que se
está ejecutando actualmente.

yield()

Este método hace que el intérprete cambie de contexto entre el hilo actual y el
siguiente hilo ejecutable disponible. Es una manera de asegurar que nos hilos de
menor prioridad no sufran inanición.

sleep( long )

El método sleep() provoca que el intérprete ponga al hilo en curso a dormir


durante el número de milisegundos que se indiquen en el parámetro de
invocación. Una vez transcurridos esos milisegundos, dicho hilo volverá a estar
disponible para su ejecución. Los relojes asociados a la mayor parte de los
intérpretes de Java no serán capaces de obtener precisiones mayores de 10
milisegundos, por mucho que se permita indicar hasta nanosegundos en la
llamada alternativa a este método.

Métodos de Instancia

Aquí no están recogidos todos los métodos de la clase Thread, sino solamente los
más interesantes, porque los demás corresponden a áreas en donde el estándar
de Java no está completo, y puede que se queden obsoletos en la próxima versión
del JDK, por ello, si se desea completar la información que aquí se expone se ha
de recurrir a la documentación del interfaz de programación de aplicación (API) del
JDK.

start()

Este método indica al intérprete de Java que cree un contexto del hilo del sistema
y comience a ejecutarlo. A continuación, el método run() de este hilo será
invocado en el nuevo contexto del hilo. Hay que tener precaución de no llamar al
método start() más de una vez sobre un hilo determinado.

run()

El método run() constituye el cuerpo de un hilo en ejecución. Este es el único


método del interfaz Runnable. Es llamado por el método start() después de que el
hilo apropiado del sistema se haya inicializado. Siempre que el método run()
devuelva el control, el hilo actual se detendrá.

stop()

Este método provoca que el hilo se detenga de manera inmediata. A menudo


constituye una manera brusca de detener un hilo, especialmente si este método se
ejecuta sobre el hilo en curso. En tal caso, la línea inmediatamente posterior a la
llamada al método stop() no llega a ejecutarse jamás, pues el contexto del hilo
muere antes de que stop() devuelva el control. Una forma más elegante de
detener un hilo es utilizar alguna variable que ocasione que el método run()
termine de manera ordenada. En realidad, nunca se debería recurrir al uso de este
método.

suspend()

El método suspend() es distinto de stop(). suspend() toma el hilo y provoca que se


detenga su ejecución sin destruir el hilo de sistema subyacente, ni el estado del
hilo anteriormente en ejecución. Si la ejecución de un hilo se suspende, puede
llamarse a resume() sobre el mismo hilo para lograr que vuelva a ejecutarse de
nuevo.

resume()

El método resume() se utiliza para revivir un hilo suspendido. No hay garantías de


que el hilo comience a ejecutarse inmediatamente, ya que puede haber un hilo de
mayor prioridad en ejecución actualmente, pero resume() ocasiona que el hilo
vuelva a ser un candidato a ser ejecutado.

setPriority( int )

El método setPriority() asigna al hilo la prioridad indicada por el valor pasado como
parámetro. Hay bastantes constantes predefinidas para la prioridad, definidas en
la clase Thread, tales como MIN_PRIORITY, NORM_PRIORITY y
MAX_PRIORITY, que toman los valores 1, 5 y 10, respectivamente. Como guía
aproximada de utilización, se puede establecer que la mayor parte de los procesos
a nivel de usuario deberían tomar una prioridad en torno a NORM_PRIORITY. Las
tareas en segundo plano, como una entrada/salida a red o el nuevo dibujo de la
pantalla, deberían tener una prioridad cercana a MIN_PRIORITY. Con las tareas a
las que se fije la máxima prioridad, en torno a MAX_PRIORITY, hay que ser
especialmente cuidadosos, porque si no se hacen llamadas a sleep() o yield(), se
puede provocar que el intérprete Java quede totalmente fuera de control.

getPriority()
Este método devuelve la prioridad del hilo de ejecución en curso, que es un valor
comprendido entre uno y diez.

setName( String )

Este método permite identificar al hilo con un nombre menmónico. De esta manera
se facilita la depuración de programas multihilo. El nombre mnemónico aparecerá
en todas las líneas de trazado que se muestran cada vez que el intérprete Java
imprime excepciones no capturadas.

getName()

Este método devuelve el valor actual, de tipo cadena, asignado como nombre al
hilo en ejecución mediante setName().

Funcionalidad de los hilos

Al igual que los procesos, los hilos poseen un estado de ejecución y pueden
sincronizarse entre ellos para evitar problemas de compartimiento de recursos.
Generalmente, cada hilo tiene una tarea especifica y determinada, como forma de
aumentar la eficiencia del uso del procesador.

Estados de un hilo

Los principales estados de los hilos son: Ejecución, Listo y Bloqueado. No tiene
sentido asociar estados de suspensión de hilos ya que es un concepto de proceso.
En todo caso, si un proceso está expulsado de la memoria principal (ram), todos
sus hilos deberán estarlo ya que todos comparten el espacio de direcciones del
proceso.

Cambio de estados

 Creación: Cuando se crea un proceso se crea un hilo para ese proceso.


Luego, este hilo puede crear otros hilos dentro del mismo proceso,
proporcionando un puntero de instrucción y los argumentos del nuevo hilo.
El hilo tendrá su propio contexto y su propio espacio de la columna, y
pasara a la final de los listos.

 Bloqueo: Cuando un hilo necesita esperar por un suceso, se bloquea


(salvando sus registros de usuario, contador de programa y punteros de
pila). Ahora el procesador podrá pasar a ejecutar otro hilo que esté en la
final de los Listos mientras el anterior permanece bloqueado.
 Desbloqueo: Cuando el suceso por el que el hilo se bloqueó se produce, el
mismo pasa a la final de los Listos.

 Terminación: Cuando un hilo finaliza se liberan tanto su contexto como sus


columnas..

Sincronización de hilos

Todos los hilos comparten el mismo espacio de direcciones y otros recursos como
pueden ser archivos abiertos. Cualquier modificación de un recurso desde un hilo
afecta al entorno del resto de los hilos del mismo proceso.Por lo tanto, es
necesario sincronizar la actividad de los distintos hilos para que no interfieran unos
con otros o corrompan estructuras de datos.

Una ventaja de la programación multihilo es que los programas operan con mayor
velocidad en sistemas de computadores con múltiples CPUs (sistemas
multiprocesador o a través de grupo de máquinas) ya que los hilos del programa
se prestan verdaderamente para la ejecución concurrente. En tal caso el
programador necesita ser cuidadoso para evitar condiciones de carrera (problema
que sucede cuando diferentes hilos o procesos alteran datos que otros también
están usando), y otros comportamientos no intuitivos. Los hilos generalmente
requieren reunirse para procesar los datos en el orden correcto. Es posible que los
hilos requieran de operaciones atómicas para impedir que los datos comunes sean
cambiados o leídos mientras estén siendo modificados, para lo que usualmente se
utilizan los semáforos. El descuido de esto puede generar interbloqueo.

Formas de multihilos

Los sistemas operativos generalmente implementan hilos de dos maneras:

 Multihilo apropiativo: permite al sistema operativo determinar cuándo debe


haber un cambio de contexto. La desventaja de esto es que el sistema
puede hacer un cambio de contexto en un momento inadecuado, causando
un fenómeno conocido como inversión de prioridades y otros problemas.

 Multihilo cooperativo: depende del mismo hilo abandonar el control cuando


llega a un punto de detención, lo cual puede traer problemas cuando el hilo
espera la disponibilidad de un recurso.

El soporte de hardware para multihilo se encuentra disponible desde hace


relativamente poco tiempo. Esta característica fue introducida por Intel en el
Pentium 4, bajo el nombre de HyperThreading.

Usos más comunes


Los usos más comunes son en tecnologías SMPP y SMS para la
telecomunicaciones aquí hay muchísimos procesos corriendo a la vez y todos
requiriendo de un servicio.

Crear un Hilo

Crear un hilo en java es una tarea muy sencilla. Basta heredar de la


clase Thread y definir el método run(). Luego se instancia esta clase y se llama al
método start() para que arranque el hilo. Más o menos esto

public MiHilo extends Thread


{
   public void run()
   {
      // Aquí el código pesado que tarda mucho
   } 
};
...
MiHilo elHilo = new MiHilo();
elHilo.start();
System.out.println("Yo sigo a lo mio");

Listo. Hemos creado una clase MiHilo que hereda de Thread y con un


método run(). En el método run() pondremos el código que queremos que se
ejecute en un hilo separado. Luego instanciamos el hilo con un new MiHilo() y lo
arrancamos con elHilo.start(). El System.out que hay detrás se ejecutará
inmediatamente después del start(), haya terminado o no el código del hilo.

3.2 Comparación Programa Flujo Único y Flujo Múltiple

Un programa de flujo único o mono-hilvanado (single-thread) utiliza un único flujo


de control (thread) para controlar su ejecución. Muchos programas no necesitan la
potencia o utilidad de múltiples flujos de control. Sin necesidad de especificar
explícitamente que se quiere un único flujo de control, muchos de los applets y
aplicaciones son de flujo único.
Por ejemplo, en la archiconocida aplicación estándar de saludo:

public class Hola Mundo? {


static public void main( String args[] ) {

System.out.println( “Hola Mundo!” );

Aquí, cuando se llama a main(), la aplicación imprime el mensaje y termina. Esto


ocurre dentro de un único hilo de ejecución (thread).

Debido a que la mayor parte de los entornos operativos no solían ofrecer un


soporte razonable para múltiples hilos de control, los lenguajes de programación
tradicionales, tales como C++, no incorporaron mecanismos para describir de
manera elegante situaciones de este tipo. La sincronización entre las múltiples
partes de un programa se llevaba a cabo mediante un bucle de suceso único.
Estos entornos son de tipo síncrono, gestionados por sucesos. Entornos tales
como el de Macintosh de Apple, Windows de Microsoft y X11/Motif fueron
diseñados en torno al modelo de bucle de suceso.

Programas de flujo múltiple

En la aplicación de saludo, no se ve el hilo de ejecución que corre el programa.


Sin embargo, Java posibilita la creación y control de hilos de ejecución
explícitamente. La utilización de hilos (threads) en Java, permite una enorme
flexibilidad a los programadores a la hora de plantearse el desarrollo de
aplicaciones. La simplicidad para crear, configurar y ejecutar hilos de ejecución,
permite que se puedan implementar muy poderosas y portables
aplicaciones/applets que no se puede con otros lenguajes de tercera generación.
En un lenguaje orientado a Internet como es Java, esta herramienta es vital.

Si se ha utilizado un navegador con soporte Java, ya se habrá visto el uso de


múltiples hilos en Java. Habrá observado que dos applets se pueden ejecutar al
mismo tiempo, o que puede desplazar la página del navegador mientras el applet
continúa ejecutándose. Esto no significa que el applet utilice múltiples hiloss, sino
que el navegador es multihilo, multihilvanado o multithreaded.

Los navegadores utilizan diferentes hilos ejecutándose en paralelo para realizar


varias tareas, “aparentemente” concurrentemente. Por ejemplo, en muchas
páginas web, se puede desplazar la página e ir leyendo el texto antes de que
todas las imágenes estén presentes en la pantalla. En este caso, el navegador
está trayéndose las imágenes en un hilo de ejecución y soportando el
desplazamiento de la página en otro hilo diferente.

Las aplicaciones (y applets) multihilo utilizan muchos contextos de ejecución para


cumplir su trabajo. Hacen uso del hecho de que muchas tareas contienen
subtareas distintas e independientes. Se puede utilizar un hilo de ejecución para
cada subtarea.

Mientras que los programas de flujo único pueden realizar su tarea ejecutando las
subtareas secuencialmente, un programa multihilo permite que cada thread
comience y termine tan pronto como sea posible. Este comportamiento presenta
una mejor respuesta a la entrada en tiempo real.

Vamos a modificar el programa de saludo creando tres hilos de ejecución


individuales, que imprimen cada uno de ellos su propio mensaje de saludo, Multi
Hola.java:

// Definimos unos sencillos hilos. Se detendrán un rato

// antes de imprimir sus nombres y retardos

class Test Th? extends Thread {


private String nombre;

private int retardo;


// Constructor para almacenar nuestro nombre

// y el retardo

public Test Th( String s,int d ) {

nombre = s;

retardo = d;

// El metodo run() es similar al main(), pero para

// threads. Cuando run() termina el thread muere

public void run() {

// Retasamos la ejecución el tiempo especificado

try {

sleep( retardo );

} catch( Interrupted Exception e ) {

// Ahora imprimimos el nombre


System.out.println( “Hola Mundo! “+nombre+” “+retardo );

public class Multi Hola {


public static void main( String args[] ) {

Test Th t1,t2,t3;

// Creamos los threads

t1 = new Test Th( “Thread 1″,(int)(Math.random()*2000) );

t2 = new Test Th( “Thread 2″,(int)(Math.random()*2000) );

t3 = new Test Th( “Thread 3″,(int)(Math.random()*2000) );

// Arrancamos los threads

t1.start();

t2.start();

t3. start();

}
3.3 Creación y Control de Hilos

En Java, los hilos comparten el mismo espacio de memoria. Incluso comparten


gran parte del entorno de ejecución, de modo que la creación de nuevos hilos es
mucho más rápida que la creación de nuevos procesos. La ventaja que
proporcionan los hilos es la capacidad de tener más de un camino de ejecución en
un mismo programa. Así, con un único proceso, ejecutándose una JVM (Java
Virtual Machine), habrá siempre más de un hilo, cada uno con su propio camino de
ejecución.

En cuanto al proceso de creación de hilos, son dos los mecanismos que nos
permiten llevarlo a cabo en Java: implementando la interfaz Runnable, o
extendiendo la clase Thread, esto es, creando una subclase de esta clase.

Lo más habitual es crear hilos implementando la interfaz Runnable, dado que


lasinterfaces representan una forma de encapsulamiento del trabajo que una clase
debe realizar.

Así, se utilizan para el diseño de requisitos comunes a todas las clases que se
tiene previsto implementar. La interfaz define el trabajo, la funcionalidad que debe
cubrirse, mientras que la clase o clases que implementan la interfaz realizan dicho
trabajo (cumplen esa funcionalidad).

Todas las clases o grupos de clases que implementen una cierta interfaz deberán
seguir las mismas reglas de funcionamiento.

El otro mecanismo de creación de hilos, como ya hemos dicho, consistiría en la


creación previa de una subclase de la clase Thread, la cual podríamos instanciar
después.

Por ejemplo,

class Mi Thread extends Thread {

public void run() {

...
}

se corresponde con la declaración de un clase, Mi Thread, que extiende la clase


Thread, sobrecargando el método Thread.run heredado con su propia
implementación.

Es en el método run donde se implementa el código correspondiente a la acción


(la tarea) que el hilo debe desarrollar . El método run no es invocado directa o
explícitamente (a menos que no quieras que se ejecute dentro de su propio hilo).
En lugar de esto, los hilos se arrancan con el método start, se suspenden con el
método suspend, se reanudan con el método resume, y se detienen con el método
stop (el cual supone también la muerte del hilo y la correspondiente
excepción Thread Death?), como ya explicaremos en el apartado de Estado y
Control de Hilos. Un hilo suspendido puede reanudarse en la instrucción del
método run en la que fue suspendido.

En el caso de crear un hilo extendiendo la clase Thread, se pueden heredar los


métodos y variables de la clase padre. Si es así, una misma subclase solamente
puede extender o derivar una vez de la clase padre Thread. Esta limitación de
Java puede ser superada a través de la implementación de Runnable. Veamos el
siguiente ejemplo:

public class Mi Thread implements Runnable {

Thread t;

public void run() {

// Ejecución del thread una vez creado

}
En este caso necesitamos crear una instancia de Thread antes de que el sistema
pueda ejecutar el proceso como un hilo. Además, el método abstracto run que
está definido en la interfaz Runnable tiene que implementarse en la nueva clase
creada.

La diferencia entre ambos métodos de creación de hilos en Java radica en la


flexibilidad con que cuenta el programador, que es mayor en el caso de la
utilización de la interfaz Runnable.

Sobre la base del ejemplo anterior, se podría extender la clase Mi Thread a


continuación, si fuese necesario. La mayoría de las clases creadas que necesiten
ejecutarse como un hilo implementarán la interfaz Runnable, ya que así queda
cubierta la posibilidad de que sean extendidas por otras clases.

Por otro lado, es un error pensar que la interfaz Runnable está realizando alguna
tarea mientras un hilo de alguna clase que la implemente se está ejecutando. Es
una interfaz, y como tal, sólo contiene funciones abstractas (concretamente una
única, run), proporcionando tan solo una idea de diseño, de infraestructura, de la
clase Thread, pero ninguna funcionalidad. Su declaración en Java tiene el
siguiente aspecto:

package Java.lang;

public interfaz Runnable {

public abstract void run() ;

Comentados los aspectos más importantes de la interfaz Runnable, veamos ahora


la definición de la clase Thread, de la cual podemos deducir lo que realmente se
está haciendo:

public class Thread implements Runnable {


public void run() {

Java Threads (Hilos en Java)

if( tarea != null )

tarea.run() ;

…}

Se deduce, por tanto, que la propia clase Thread de Java también implementa la
interfaz Runnable. Observamos que en el método run de Thread se comprueba si
la clase con que se está trabajando en ese momento (tarea), que es la clase que
se pretende ejecutar como hilo, es o no nula. En caso de no ser nula, se invoca al
método run propio de dicha clase.

Control de un hilo

Arranque de un hilo

En el contexto de las aplicaciones, sabemos que es main la primera función que


se invoca tras arrancar, y por tanto, lógicamente, es el lugar más apropiado para
crear y arrancar otros hilos.

La línea de código:

t1 = new Test Th?( “Thread 1″,(int)(Math.random()*2000) );


siendo Test Th una subclase de la clase Thread (o una clase que implemente la
interfaz

Runnable) crea un nuevo hilo. Los dos argumentos pasados, sin mayor relevancia,
satisfarán

el prototipo del constructor de la clase y se utilizarán para la inicialización del


objeto.

Al tener control directo sobre los hilos, tenemos que arrancarlos explícitamente.
Como ya se comentó anteriormente, es la función miembro start la que nos
permite hacerlo. En nuestro

ejemplo sería:

t1.start();

start, en realidad es un método oculto en el hilo que llama al método run.

Manipulación de un hilo

Si todo fue bien en la creación del objeto Test Th (t1), éste debería contener un
hilo, una traza de ejecución válida, que controlaremos en el método run del objeto.

El cuerpo de esta función miembro viene a ser el cuerpo de un programa como ya


los conocemos. Digamos que es la rutina main a nivel de hilo. Todo lo que
queremos que haga el hilo debe estar dentro del método run. Cuando finalice run,
finalizará también el hilo que lo ejecutaba.

Suspensión de un Hilo

La función miembro suspend de la clase Thread permite tener un control sobre el


hilo de modo que podamos desactivarlo, detener su actividad durante un intervalo
de tiempo indeterminado, a diferencia del uso de la llamada al sistema sleep, que
simplemente lleva al hilo a un estado de “dormido”, y siempre durante un número
de milisegundos concreto.
Este método puede resultar útil si, construyendo un applet con un hilo de
animación, queremos permitir al usuario detener (que no finalizar) la animación,
hasta que éste decida reanudarla.

Este método no detiene la ejecución permanentemente. El hilo es suspendido


indefinidamente y para volver a activarlo de nuevo necesitamos realizar una
invocación a la función miembro resume.

Parada de un Hilo

Ya conocemos los métodos de control de hilos que nos permiten arrancarlos,


suspenderlos y reanudarlos. El último elemento de control que se necesita sobre
hilos es el método stop,utilizado para terminar la ejecución de un hilo de forma
permanente:

t1.stop();

Señalar que esta llamada no destruye el hilo, sino que detiene su ejecución, y ésta
no puede reanudarse con el método start. Cuando se desasignen las variables
que se usan en el hilo, el objeto hilo (creado con new) quedará marcado para
eliminarlo y el garbage collector (recolector de basura de Java) se encargará de
liberar la memoria que utilizaba.

Tiene sentido su utilidad, por ejemplo, en aplicaciones complejas que necesiten un


control sobre cada uno de los hilos que se lancen.

Por último, un método de control de hilos que nos permite comprobar si una
instancia está viva (el hilo se ha arrancado y aún no se ha detenido) o no (bien no
se arrancó; bien ya finalizó).

Estamos hablando de la función miembro isAlive.

t1.isAlive();
Devolverá true en caso de que el hilo t1 esté vivo, es decir, ya se haya llamado a
su método run y no haya sido parado con un stop ni haya terminado el método run
en su ejecución. En otro caso, lógicamente, devolverá false.

3.3.1 atributos de un hilo

Los atributos de un thread


Cada thread cuenta con diferentes propiedades que lo hacen unico. Se adopta un
enfoque orientado a objetos con respecto a la representacion y asignacion de
propiedades. Bajo este paradigma cada thread cuenta con un objeto atributo
asociado a varios threads. Los objetos atributos son del tipo:

pthread_attr_t

Los atributos/propiedades de un thread varian de una implementacion a otra. Sin


embargo a manera general los atributos que denen a un thread son:

Estado de espera: permite que otros threads esperen por la terminacion de un


thread en especial.

Direccion de stack: apuntador al inicio del stack del thread

Tamano de la direccion: longitud del stack del thread.

Alcance (scope): dene quien controla la ejecucion del thread: el proceso o el


nucleo del sistema operativo.

Herencia: los parametros de calendarizacion son heredados o denidos


localmente.

Politica de calendarizacion: la politica que va a definir que proceso se va a ejecutar


y en que instante.

FIFO
{

Round-robin

Prioridad: un valor de prioridad alto corresponde a una mayor prioridad.

Es posible modicar varios de estos atributos a traves de diferentes llamadas de


sistema.

Lafuncion pthread_attr_init

asigna los atributos de default a los threads y la funcion

pthread_attr_destroy hace que el valor del objeto atributo sea invalido.

3.3.2 Inicialización y Creación de Hilos.

Antes de poder usar cualquier función de manejo de hilos, hay que preparar el
sistema para ejecutar estas operaciones, es decir, es necesario inicializar el
sistema de hilos, nada más sencillo.

Void g_thread_init (G Thread Functions *vtable );

En la mayoría de las ocasiones bastará con que el parámetro pasado al sistema


de hilos sea nulo, de esta forma G Lib? se encargará de buscar los parámetros
más apropiados.

Es importante no llamar a esta función más de una vez pues, si esto sucediese, la
ejecución de nuestro programa sería abortada. Para evitar esto la forma más
sencilla es hacer:
if (!g_thread_supported ())

g_thread_init (NULL);
Después, el sistema estará listo para realizar cualquier operación que requiera el
uso de hilos. Para empezar, se creará un hilo:

G Thread? *hilo:
hilo = g_thread_create (funcion_hilo, NULL, FALSE, NULL);

A partir de este punto, el procedimiento funcion_hilo se ejecutará en un hilo


diferente, el programa continuará su ejecución normal y, en paralelo a él, se
ejecutará esta función.

3.3.3 Manipulación de hilos

Si todo fue bien en la creación del objeto Test Th? (t1), éste debería contener un
hilo, una traza

de ejecución válida, que controlaremos en el método run del objeto.

El cuerpo de esta función miembro viene a ser el cuerpo de un programa como ya


los

conocemos. Digamos que es la rutina main a nivel de hilo. Todo lo que queremos
que haga el hilo debe estar dentro del método run. Cuando finalice run, finalizará
también el hilo que lo

ejecutaba.

3.3.4 Suspensión de un Hilo

La función miembro suspend de la clase Thread permite tener un control sobre el


hilo de modo que podamos desactivarlo, detener su actividad durante un intervalo
de tiempo indeterminado, a diferencia del uso de la llamada al sistema sleep, que
simplemente lleva al

hilo a un estado de “dormido”, y siempre durante un número de milisegundos


concreto.
Este método puede resultar útil si, construyendo un applet con un hilo de
animación,

queremos permitir al usuario detener (que no finalizar) la animación, hasta que


éste decida reanudarla.

Este método no detiene la ejecución permanentemente. El hilo es suspendido


indefinidamente y para volver a activarlo de nuevo necesitamos realizar una
invocación a la función miembro resume.

3.3.5 Parada De Hilos


Suspensión de un Hilo

 El último elemento de control que se necesita sobre los hilos de ejecución es el
método stop(). Se utiliza para terminar la ejecución de un hilo:

t1.stop();

Esta llamada no destruye el hilo, sino que detiene su ejecución. La ejecución no se


puede reanudar ya con t1.start(). Cuando se desasignen las variables que se usan
en el hilo, el objeto Thread (creado con new) quedará marcado para eliminarlo y el
garbage collector se encargará de liberar la memoria que utilizaba.

Si se necesita, se puede comprobar si un hilo está vivo o no; considerando vivo un


hilo que ha comenzado y no ha sido detenido.
t1.isAlive();

Este método devolverá true en caso de que el hilo t1 esté vivo, es decir, ya se
haya llamado a su método run() y no haya sido parado con un stop() ni haya
terminado el método run() en su ejecución.

En el ejemplo no hay problemas de realizar una parada incondicional, al estar


todos los hilos vivos. Pero si a un hilo de ejecución, que puede no estar vivo, se le
invoca su método stop(), se generará una excepción. En este caso, en los que el
estado del hilo no puede conocerse de antemano es donde se requiere el uso del
método isAlive().
3.4 Sincronización de hilos

Sincronización

El problema de la sincronización de hilos tiene lugar cuando varios hilos intentan


acceder al mismo recurso o dato. A la hora de acceder a datos comunes, los hilos
necesitan establecer cierto orden, por ejemplo en el caso del productor
consumidor. Para asegurarse de que hilos concurrentes no se estorban y operan
correctamente con datos (o recursos) compartidos, un sistema estable previene la
inanición y el punto muerto o interbloqueo. La inanición tiene lugar cuando uno o
más hilos están bloqueados al intentar conseguir acceso a un recurso compartido
de ocurrencias limitadas. El interbloqueo es la última fase de la inanición; ocurre
cuando uno o más hilos están esperando una condición que no puede ser
satisfecha. Esto ocurre muy frecuentemente cuando dos o más hilos están
esperando a que el otro u otros se desbloquee, respectivamente.

3.5 SEMAFOROS

Los semáforos se pueden considerar primitivas de bajo nivel en comparación con


otros modelos de paso de mensajes. Debido a su dificultad de utilización, resultan
poco apropiados para utilizar en los programas, por lo que se debería limitar a
módulos muy definidos.

Tipos de semáforos

Los semáforos operan con enteros no negativos. En función del rango de valores
posibles, hay dos tipos de semáforos:

Binarios: toman valores 0 y 1

Generales: toman los valores mayores de 0

Los lenguajes de programación normalmente trabajan con semáforos generales.


En caso de que no fuera así, se podrían implementar con semáforos binarios.
3.6 Barreras Barrier
BARRERA

Enunciado. Un proceso crea N hilos. El comportamiento de cada uno consiste en


la ejecución de un bucle con tres partes:

BARRERA

En cada iteración del bucle los hilos ejecutarán A sin realizar ninguna
sincronización; a continuación todos ellos esperan a que el resto llegue a la
BARRERA. Una vez que todos han llegado a la barrera (todos han ejecutado A),
continúan ejecutando B y el bucle se repite.
Salidas. Cada hilo deberá informar del número de iteración junto con el punto del
bucle que acaba de ejecutar.

Finalización. Ejecutar la iteración un cierto número de veces

Esquema del problema

Muchos problemas de cálculo se pueden resolver de acuerdo al siguiente


esquema:

Ejemplos:

–procesamiento de imágenes

–funciones definidas sobre mallas de puntos

–resolución de sistemas de ecuaciones

–problemas de optimización, etc.


La ejecución de “esperar al resto de procesos” es una sincronización, este tipo se
denomina “sincronización por barrera”.

Conclusión:

Los hilos a menudo son conocidos o llamados procesos ligeros. Un hilo, en


efecto, es muy similar a un proceso pero con la diferencia de que un hilo siempre
corre dentro del contexto de otro programa. Por el contrario, los procesos
mantienen su propio espacio de direcciones y entorno de operaciones. Los hilos
dependen de un programa padre en lo que se refiere a recursos de ejecución. La
siguiente figura muestra le relación entre hilos y procesos.

En Java, los hilos comparten el mismo espacio de memoria. Incluso comparten


gran parte del entorno de ejecución, de modo que la creación de nuevos hilos es
mucho más rápida que la creación de nuevos procesos. La ventaja que
proporcionan los hilos es la capacidad de tener más de un camino de ejecución en
un mismo programa. Así, con un único proceso, ejecutándose una JVM (Java
Virtual Machine), habrá siempre más de un hilo, cada uno con su propio camino de
ejecución.
Bibliografía:

1."Java como programar". Deitel y Deitel. 5º edición,

Pearson Education 2004.

2. "Programación en Java", Mora Rodríguez, Frank.Año: 2006.

3. http://www.lawebdelprogramador.com

4. "Aprenda Java como si estuviera en Primero".García de Jalón, Javier.


Rodríguez, José Ignacio.y otros. Escuela Superior de Ingenieros
Industriales. Universidad de Navarra. Marzo, 1999.

5. "Introducción a Java". Chojrin, Mauro. Año 2006.

BIBLIOGRAFIA

Elaborada por: Programación Avanzada y Métodos Numéricos


Ing. Laura Sandoval Montaño
Viridiana del Carmen De Luna Bonilla
Virgilio Green Pérez
Ejemplo 1

http://www.hackerdude.com/courses/delphi/Cap011.1.html

You might also like