miércoles, 30 de abril de 2014

COMUNICACIÓN DEL APPLET CON EL BROWSER - I

La comunicación entre el applet y el browser en el que se está ejecutando se puede controlar mediante la interface AppíetContext (package java.applet). AppletContext es una interface implementada por el browser. cuyos métodos pueden ser utilizados por el applet para obtener información y realizar ciertas operaciones, como por ejemplo sacar mensajes breves en la barra de estado del browser. Hay que tener en cuenta que la baña de estado es compartida por el browser y las applets. lo que tiene el peligro de que el mensaje sea rápidamente sobre-escrito por el browser u otras applets y que el usuario no llegue a enterarse del mensaje.
 Los mensajes breves a la barra de estado se producen con el método showStatus(). como por ejemplo,

getAppletContext().showStatus("Cargado desde el fichero " + filename);

Los mensajes más importantes se deben dirigir a la salida estándar o a la salida de errores, que en Netscape Navigator es la Java Consolé (la cual se hace visible desde el menú Options en Navigator 3.0. desde el menú Communicator en Navigator 4.0* y desde Communicator/Tools en Navigator 4.5). Estos mensajes se pueden enviar con las sentencias:

System.out.print();
System.out.println();
System.error.print();
System.error.println();

martes, 29 de abril de 2014

CARGA DE APPLETS

Localizacióii de ficheros 
Por defecto se supone que los ficheros *.class del applet están en el mismo directorio que el fichero HTML. Si el applet pertenece a un pac ka ge. el browser utiliza el nombre del package para construir unpath de directorio relativo al directorio donde está el HTML. El atributo CODEBASE permite definir un URL para los ficheros que continen el código y demás elementos del applet. Si el directorio definido por el URL de CODEBASE es relativo. se interpreta respecto al directorio donde está el HTML: si es absoluto se interpreta en sentido estricto y puede ser cualquier directorio de la Internet. 
Archivos JAR (Java Archives) 
Si un applet consta de varias clases, cada fichero *.class requiere una conexión con el servidor de Web (servidor de protocolo HTTP), lo cual puede requerir algunos segundos. En este caso es conveniente agrupar todos los ficheros en un archivo único, que se puede comprimir y cargar con una sola conexión HTTP. Los archivos JAR están basados en los archivos ZIP y pueden crearse con el programa jar que viene con el JDK. Por ejemplo:

jar cvf myFile.jar *.class *.gif

crea un fichero llamado myFile.jar que contiene todos los ficheros *.class y *.gif át\ directorio actual. Si las clases pertenecieran a un package llamado es.ceit.infor2 se utilizaría el comando:

jar cvf myFile.jar es\ceit\infor2\*.class *.gif

lunes, 28 de abril de 2014

PASO DE PARÁMETROS A UN APPLET

Los tags PARAM permiten pasar diversos parámetros desde el fichero HTML al programa Java del applet. de una fonna análoga a la que se utiliza para pasar argumentos a main(). 
Cada parámetro tiene un nombre y un valor. Ambos se dan en forma de String. aunque el valor sea numérico. El applet recupera estos parámetros y. si es necesario, convierte los Strings en valores numéricos. El valor de los parámetros se obtienen con el siguiente método de la clase Applet:

String getParameter(String ñame)

La conversión de Strings a los tipos primitivos se puede hacer con los métodos asociados a los wrappers que Java proporciona para dichos tipo fundamentales (Integer.parselnt(String), Double.valueOf(String), ...). Estas clases de wrappers se estudiaron en el Apartado 4.3. a partir de la página 69. En los nombres de los parámetros no se distingue entre mayúsculas y minúsculas, pero sí en los valores, ya que serán interpretados por un programa Java, que sí distingue. 
El programador del applet debería prever siempre unos valores por defecto para los parámetros del applet. para el caso de que en la página HTML que llama al applet no se definan. El método getParameterInfo() devuelve una matriz de Strings (String[][]) con información sobre cada uno de los parámetros soportados por el applet: nombre, tipo y descripción, cada uno de ellos en un String. Este método debe ser redeñnido por el programador del applet y utilizado por la persona que prepara la página HTML que llama al applet. En muchas ocasiones serán personas distintas, y ésta es una fonna de que el programador del applet dé información al usuario.

domingo, 27 de abril de 2014

CÓMO INCLUIR UN APPLET EN UNA PÁGINA HTML

Para llamar a un applet desde una página HTML se utiliza la tag doble <applet>...&lt; APPLET&gt;,
cuya fonna general es (los elementos opcionales aparecen entre corchetes[ ]

<APPLET C0DE="miApplet.class" [C0DEBASE="unURL"] [NAME=nunName"]
WIDTH="wpixels" HEIGHT="hpixe1s"
[ALT="TextoAlternativo"]>
[texto alternativo para browsers que reconocen el tag <applet> pero no pueden

ejecutar el applet]
[<?ARAM NAME="MyName1" VALUE="valueOfMyNamel">]
[<PARAM NAME="MyNaine2" VALüE=,,valueOfMyName2">]
</APPLET>

El atributo ÑAME permite dar un nombre opcional al applet. con objeto de poder comunicarse con otras applets o con otros elementos que se estén ejecutando en la misma página. El atributo ARCHIVE permite indicar uno o varios ficheros Jar o Zip (separados por comas) donde se deben buscar las clases.
A continuación se señalan otros posibles atributos de <APPLET>:

• ARCHIVE-'file 1. file2. file3". Se utiliza para especificar ficheros JAR y ZIP.

• ALIGN. VSPACE. HSPACE. Tienen el mismo significado que el tag IMG de HTML.
: • ARCHIVE-'file 1. file2. file3". Se utiliza para especificar ficheros JAR y ZIP. • ALIGN. VSPACE. HSPACE. Tienen el mismo significado que el tag IMG de HTML.

sábado, 26 de abril de 2014

Métodos para dibujar el applet

Las applets son aplicaciones gráficas que aparecen en una zona de la ventana del browser. Por ello deben redefinir los métodos gráficospaint() y update(). El métodopaintQ se declara en la forma:

public void paint(Graphics g)

El objeto gráfico g pertenece a la clase java.ant.Graphics. que siempre debe ser importada por el applet. Este objeto define un contexto o estado gráfico para dibujar (métodos gráficos, colores, fonts. etc.) y es creado por el browser. Todo el trabajo gráfico del applet (dibujo de líneas, formas gráficas, texto, etc.) se debe incluir en el método paintQ. porque este método es llamado cuando el applet se dibuja por primera vez y también de fonna automática cada vez que el applet se debe redibujar. 
En general, el programador crea el método paitit() pero no lo suele llamar. Para pedir explícitamente al sistema que vuelva a dibujar el applet (por ejemplo, por haber realizado algún cambio) se utiliza el método repaiut(). que es más fácil de usar, pues no requiere argumentos. El método repaint() se encarga de llamar a paintf) a través de updateQ. El método repaint() llama a updateQ. que borra todo pintando de nuevo con el color de fondo y luego llama a paintQ. A veces esto produce parpadeo de pantalla o flickering. Existen dos formas de evitar el flickering-. 
1. Redefinir updateQ de fonna que no borre toda la ventana sino sólo lo necesario. 
2. Redefinir paintQ y updateQ para utilizar doble buffer. Ambas formas fueron consideradas en los Apartados 5.6.1 y 5.6.2. en la página 123.

viernes, 25 de abril de 2014

Métodos que controlan la ejecución de un applet

Los métodos que se estudian en este Apartado controlan la ejecución de las applets. De ordinario el programador tiene que re de finir uno o más de estos métodos, pero no tiene que preocuparse de llamarlos: el browser se encarga de hacerlo. 
Método initO Se llama automáticamente al método initQ en cuanto el browser o visualizador carga el applet. Este método se ocupa de todas las tareas de inicialización. realizando las funciones del constructor (al que el browser no llama). En Netscape Navigator se puede reinicializar un applet con Shift+Reload.
Método start() El método start() se llama automáticamente en cuanto el applet se hace visible, después de haber sido inicializada. Se llama también cada vez que el applet se hace de nuevo visible después de haber estado oculta (por dejar de estar activa esa página del browser. al cambiar el tamaño de la ventana del browser. al hacer reload. etc.). Es habitual crear threads en este método para aquellas tareas que. por el tiempo que requieren, dejarían sin reclusos al applet o incluso al browser. Las animaciones y ciertas tareas a través de Internet son ejemplos de este tipo de tareas. 
Método stop() El método stop() se llama de fonna automática al ocultar el applet (por haber haber dejado de estar activa la página del browser. por hacer reload o resize. etc.). Con objeto de no consumir reclusos inútilmente, en este método se suelen parar las threads que estén corriendo en el applet. por ejemplo para mostrar animaciones. 
Método destroy() Se llama a este método cuando el applet va a ser descargada para liberar los reclusos que tenga reservados (excepto la memoria). De ordinario no es necesario redefinir este método, pues el que se hereda cumple bien con esta misión.

jueves, 24 de abril de 2014

Algunas características de las applets

Las características de las applets se pueden considerar desde el punto de vista del programador y desde el del usuario. En este manual lo más importante es el punto de vista del programador: 
• Las applets no tienen mi método main() con el que comience la ejecución. El papel central de su ejecución lo asumen otros métodos que se verán posteriormente. 
• Todas las applets derivan de la clase java.applet.Applet. La Figura 7.1 muestra la jerarquía de clases de la que deriva la clase Applet. Las applets deben redefinir ciertos métodos heredados de Applet que controlan su ejecución: initQ, start(). stop(). destroy(). 
• Se heredan otros muchos métodos de las super-clases de Applet que tienen que ver con la generación de interfaces gráficas de usuario (AWT). Así. los métodos gráficos se heredan de Componente mientras que la capacidad de añadir componentes de interface de usuario se hereda de Container y de Panel. 
• Las applets también suelen redefinir ciertos métodos gráficos: los más importantes son paint() y update(). heredados de Component y de Container: y repaint() heredado de Component. 
• Las applets disponen de métodos relacionados con la obtención de información, como por ejemplo: getAppletlnfof), getAppletContextf), getParameterInfo(). getParameter(), getCodeBasef). getDocutnentBase(). e isActive(). El método showStatusQ se utiliza para mostrar información en la barra de estado del browser. Existen otros métodos relacionados con imágenes y sonido: getlmagef). getAudioClip(). play(). etc.

miércoles, 23 de abril de 2014

APPLETS

QUÉ ES UN APPLET 

Un applet es una mini-aplicación, escrita en Java. que se ejecuta en un browser (.Netscape Navigator. Microsoft Internet Explorer. ...) al cargar una página HTML que incluye información sobre el applet a ejecutar por medio de las tags ... . A continuación se detallan algunas características de las applets: 
1. Los ficheros de Java compilados (*.class) se descargan a través de la red desde un servidor de Web o servidor HTTP hasta el browser en cuya Java Virtual Machine se ejecutan. Pueden incluir también ficheros de imágenes y sonido. 
2. Las applets no tienen ventana propia: se ejecutan en la ventana del browser (en un "panel"). 3. Por la propia naturaleza "abierta" de Internet, las applets tienen importantes restricciones de seguridad, que se comprueban al llegar al browser: sólo pueden leer y escribir ficheros en el servidor del que han venido, sólo pueden acceder a una limitada información sobre el ordenador en el que se están ejecutando, etc. 

Con ciertas condiciones, las applets "de confianza'' (tr usted applets) pueden pasar por encima de estas restricciones. Aunque su entorno de ejecución es un browser. las applets se pueden probar sin necesidad de browser con la aplicación appletviewer del JDK de Sun.

martes, 22 de abril de 2014

GRUPOS DE THREADS

Todo hilo de Java debe formar parte de un grupo de hilos (ThreadGroup). Puede pertenecer al grupo por defecto o a uno explícitamente creado por el usuario. Los grupos de threads proporcionan una fonna sencilla de manejar múltiples threads como un solo objeto. Así. por ejemplo es posible parar varios threads con una sola llamada al método correspondiente. Una vez que un thread ha sido asociado a un threadgroup. no puede cambiar de grupo.
Cuando se arranca mi programa, el sistema crea un ThreadGroup llamado main. Si en la creación de un nuevo thread no se especifica a qué grupo pertenece, automáticamente pasa a pertenecer al threadgroup del thread desde el que ha sido creado (conocido como current thread group y current thread. respectivamente). Si en dicho programa no se crea ningún ThreadGroup adicional, todos los threads creados pertenecerán al grupo main (en este grupo se encuentra el método mainff). La Figura 6.3 presenta una posible distribución de threads distribuidos en grupos de threads. Para conseguir que un thread pertenezca a un grupo concreto, hay que indicarlo al crear el nuevo thread. según uno de los siguientes constructores: 

public Thread (ThreadGroup grupo, Runnable destino)
public Thread (ThreadGroup grupo, String nombre)

public Thread (ThreadGroup grupo, Runnable destino, String nombre)
A su vez. un ThreadGroup debe pertenecer a otro ThreadGroup. Como ocurría en el caso anterior, si no se especifica ninguno, el nuevo grupo pertenecerá al ThreadGroup desde el que ha sido creado (por defecto al grupo main). 
La clase ThreadGroup tiene dos posibles constructores: ThreadGroup(ThreadGroup parent, String nombre); ThreadGroup(String ñame); el segundo de los cuales toma como parent el threadgroup al cual pertenezca el thread desde el que se crea (Thread.currentThreadQ). Para más información acerca de estos constructores, dirigirse a la documentación del API de Java donde aparecen numerosos métodos para trabajar con grupos de threads a disposición del usuario (getMaxPriority(). setMaxPriority(). getName(). getParentf), parentOfO). En la práctica los ThreadGroups no se suelen utilizar demasiado. 
Su uso práctico se limita a efectuar determinadas operaciones de fonna más simple que de fonna individual. En cualquier caso, véase el siguiente ejemplo: ThreadGroup miThreadGroup = new ThreadGroup("Mi Grupo de Threads"); Thread miThread = new Thread(miThreadGroup, "un thread para mi grupo"); donde se crea un grupo de threads (miThreadGroup) y un thread que pertenece a dicho grupo (miThread).

lunes, 21 de abril de 2014

PRIORIDADES

Con el fin de conseguir una conecta ejecución de un programa se establecen prioridades en los threads. de fonna que se produzca un reparto más eficiente de los recursos disponibles. Así. en mi determinado momento, interesará que un determinado proceso acabe lo antes posible sus cálculos, de fonna que habrá que otorgarle más recursos (más tiempo de CPU). Esto no significa que el resto de procesos no requieran tiempo de CPU. sino que necesitarán menos. La forma de llevar a cabo esto es gracias a las prioridades. 
Cuando se crea un nuevo thread. éste hereda la prioridad del thread desde el que ha sido inicializado. Las prioridades viene definidas por variables miembro de la clase Thread. que toman valores enteros que oscilan entre la máxima prioridad MAXPRIORITY (normahílente tiene el valor 10) y la mínima prioridad MIN_PRIORITY (valor 1). siendo la prioridad por defecto NORM_PRIORITY (valor 5). Para modificar la prioridad de un thread se utiliza el método setPriority(). Se obtiene su valor con getPriority(). El algoritmo de distribución de recursos en Java escoge por norma general aquel thread que tiene una prioridad mayor, aunque no siempre ocurra así. para evitar que algunos procesos queden "dormidos". 
Cuando hay dos o más threads de la misma prioridad (y además, dicha prioridad es la más elevada), el sistema no establecerá prioridades entre los mismos, y los ejecutará alternativamente dependiendo del sistema operativo en el que esté siendo ejecutado. Si dicho SO soporta el "time-slicing" (reparto del tiempo de CPU), como por ejemplo lo hace Windows 95/98/NT, los threads serán ejecutados alternativamente. 
Un thread puede en un detenninado momento renunciar a su tiempo de CPU y otorgárselo a otro thread de la misma prioridad, mediante el método yield(). aunque en ningún caso a un thread de prioridad inferior.

domingo, 20 de abril de 2014

SINCRONIZACIÓN - IV

El bucle while de la ñinción get() continúa ejecutándose (avaiaible == false) hasta que el método put() haya suministrado un nuevo valor y lo indique con avalaible = true. En cada iteración del while la ñinción waitQ hace que el hilo que ejecuta el método getQ se detenga hasta que se produzca un mensaje de que algo ha sido cambiado (en este caso con el método notifAUQ ejecutado porputQ). El métodoputQ funciona de fonna similar. Existe también la posibilidad de sincronizar una paite del código de un método sin necesidad de mantener bloqueado el objeto desde el comienzo hasta el final del método. Para ello se utiliza la palabra clave syticronized indicando entre paréntesis el objeto que se desea sincronizar (synchronized(objetoASincronizar)). Por ejemplo si se desea sincronizar el propio thread en una paite del método runQ. el código podría ser:
public void run() {
while(true) {
syncronized(this) { // El objeto a sincronizar es el propio thread
...                  // Código sincronizado
}
try {
sleep(500); // Se detiene el thread durante 0.5 segundos pero el objeto
// es accesible por otros threads al no estar sincronizado
} catch(InterruptedException e) {}
}
}
Un thread puede llamar a un método sincronizado de un objeto para el cual ya posee el bloqueo, volviendo a adquirir el bloqueo. Por ejemplo:
public class VolverAAdquirir {
public synchronized void a() {
b () ;
System.out.println("Estoy en a()");
}
public synchronized void b() {
System.out.println("Estoy en b()");
}
}
El anterior ejemplo obtendrá como resultado:

Estoy en b()
Estoy en a()


debido a que se ha podido acceder al objeto con el método b() al ser el thread que ejecuta el método a() "propietario*' con anterioridad del bloqueo del objeto. La sincronización es un proceso que lleva bastante tiempo a la CPU. luego se debe minimizar su uso. ya que el programa será más lento cuanta más sincronización incorpore.

sábado, 19 de abril de 2014

SINCRONIZACIÓN - III

Los métodos notifyf) y notifyAllf) deben ser llamados desde el thread que tiene bloqueado el objeto para activar el resto de threads que están esperando la liberación de un objeto. Un thread se convierte en propietario del bloqueo de un objeto ejecutando un método sincronizado del objeto. Los bloqueos de tipo clase, se consiguen ejecutando un método de clase sincronizado (synchronized static). Véanse las dos funciones siguientes, de las que putf) inserta un dato y getf) lo recoge:

public synchronized int get() {
while (available == false) {
try {
// Espera a que put() asigne el valor y lo comunique con notifyf)
wait();
} catch (InterruptedException e) { }
}
available = false;
// notifica que el valor ha sido leido
notifyAll();
// devuelve el valor
return contents;
}
public synchronized void put(int valué) {
while (available == true) {
try {
// Espera a que get() lea el valor disponible antes de darle otro
wait () ;
} catch (InterruptedException e) { }
}
// ofrece un nuevo valor y lo declara disponible
 contents = valué;
available = true;
// notifica que el valor ha sido cainbiado
notifyAll();
}

viernes, 18 de abril de 2014

SINCRONIZACIÓN - II

Existen dos niveles de bloqueo de un recurso. El primero es a nivel de objetos. mientras que el segundo es a nivel de clases. El primero se consigue declarando todos los métodos de una clase como synchronized. Cuando se ejecuta un método synchronized sobre un objeto concreto, el sistema bloquea dicho objeto, de fonna que si otro thread intenta ejecutar algún método sincronizado de ese objeto, este segundo método se mantendrá a la espera hasta que finalice el anterior (y desbloquee por lo tanto el objeto). 
Si existen varios objetos de una misma clase, como los bloqueos se producen a nivel de objeto, es posible tener distintos threads ejecutando métodos sobre diversos objetos de una misma clase. El bloqueo de recursos a nivel de clases se corresponde con los métodos de clase o static. y por lo tanto con las variables de clase o static. Si lo que se desea es conseguir que un método bloquee simultáneamente una clase entera, es decir todos los objetos creados de una clase, es necesario declarar este método como synchronized static. Durante la ejecución de un método declarado de esta segunda fonna ningún método sincronizado tendrá acceso a ningún objeto de la clase bloqueada. 
La sincronización puede ser problemática y generar errores. Un thread podría bloquear mi determinado recurso de fonna indefinida, impidiendo que el resto de threads accedieran al mismo. Para evitar esto último, habrá que utilizar la sincronización sólo donde sea estrictamente necesario. Es necesario tener presente que si dentro un método sincronizado se utiliza el método sleepf) de la clase Thread. el objeto bloqueado permanecerá en ese estado durante el tiempo indicado en el argumento de dicho método. Esto implica que otros threads no podrán acceder a ese objeto durante ese tiempo, aunque en realidad no exista peligro de simultaneidad ya que durante ese tiempo el thread que mantiene bloqueado el objeto no realizará cambios. Para evitarlo es conveniente sustituir sleepf) por el método yvaitQ de la clase java.lang.Object heredado automáticamente por todas las clases. 
Cuando se llama al método waitQ (siempre debe hacerse desde un método o bloque synchronized) se libera el bloqueo del objeto y por lo tanto es posible continuar utilizando ese objeto a través de métodos sincronizados. El método waitQ detiene el thread hasta que se llame al método notifyf) o notifyAllf) del objeto, o finalice el tiempo indicado como argumento del método waitQ. El método un Objeto.notifyf) lanza una señal indicando al sistema que puede activar uno de los threads que se encuentren bloqueados esperando para acceder al objeto u ti Objeto. El método notifyAllf) lanza una señal a todos los threads que están esperando la liberación del objeto

jueves, 17 de abril de 2014

SINCRONIZACIÓN - I

La sincronización nace de la necesidad de evitar que dos o más threads traten de acceder a los mismos recursos al mismo tiempo. Así. por ejemplo, si un thread tratara de escribir en un fichero, y otro thread estuviera al mismo tiempo tratando de borrar dicho fichero, se produciría una situación no deseada. Otra situación en la que hay que sincronizar threads se produce cuando un thread debe esperar a que estén preparados los datos que le debe suministrar el otro thread. Para solucionar estos tipos de problemas es importante poder sincronizar los distintos threads. 
Las secciones de código de un programa que acceden a mi mismo recurso (un mismo objeto de una clase, un fichero del disco, etc.) desde dos threads distintos se denominan secciones criticas (critical sections). Para sincronizar dos o más threads. hay que utilizar el modificador synchronized en aquellos métodos del objeto-recurso con los que puedan producirse situaciones conflictivas. De esta fonna. Java bloquea (asocia un bloqueo o lock) con el recurso sincronizado. Por ejemplo:

public synchronized void metodoSincronizado() {
...II accediendo por ejemplo a las variables de un objeto
}

La sincronización previene las interferencias solamente sobre un tipo de recurso: la memoria reservada para un objeto. Cuando se prevea que unas determinadas variables de una clase pueden tener problemas de sincronización, se deberán declarar como prívate (o protected). De esta fonna sólo estarán accesibles a través de métodos de la clase, que deberán estar sincronizados. 
Es muy importante tener en cuenta que si se sincronizan algunos métodos de un objeto pero otros no. el programa puede no funcionar correctamente. La razón es que los métodos no sincronizados pueden acceder libremente a las variables miembro, ignorando el bloqueo del objeto. Sólo los métodos sincronizados comprueban si un objeto está bloqueado. Por lo tanto, todos los métodos que accedan a un recurso compartido deben ser declarados synchronized. De esta fonna. si algún método accede a un determinado recurso. Java bloquea dicho recurso, de fonna que el resto de threads no puedan acceder al mismo hasta que el primero en acceder termine de realizar su tarea. Bloquear un recurso u objeto significa que sobre ese objeto no pueden actuar simultáneamente dos métodos sincronizados.

miércoles, 16 de abril de 2014

Finalizar un Thread

Un thread finaliza cuando el método run() devuelve el control, por haber terminado lo que tenía que hacer (por ejemplo, un bucle for que se ejecuta IUI número determinado de veces) o por haberse dejado de cumplir una condición (por ejemplo, por un bucle n-hile en el método run(f). Es habitual poner las siguientes sentencias en el caso de Applets Runnables:

public class MyApplet extends Applet implements Runnable {
// se crea una referencia tipo Thread
private Thread AppletThread;
// método start() del Applet
public void start() {
if(AppletThread == nuil){            // si no tiene un objeto Thread asociado
AppletThread = new Thread(this, "El propio Applet");
AppletThread.start();                // se arranca el thread y llama a run()
}
}
// método stop() del Applet
public void stop() {
AppletThread = nuil;                 // iguala la referencia a nuil
}
// método run() por implementar Runnable
public void run() {
Thread myThread = Thread.currentThread();
while (myThread == AppletThread) { // hasta que se ejecute stop() de Thread
...                               // código a ejecutar
}
}
} // fin de la clase MyApplet

donde AppletThread es el thread que ejecuta el método runQ MyApplet. Para finalizar el thread basta poner la referencia AppletThread a nuil. Esto se consigue en el ejemplo con el método stopf) del applet (distinto del método stopf) de la clase Thread. que no conviene utilizar). Para saber si un thread está '"vivo" o no. es útil el método isAlivef) de la clase Thread. que devuelve true si el thread ha sido inicializado y no parado, y false si el thread es todavía nuevo (no ha sido inicializado) o ha finalizado.

martes, 15 de abril de 2014

Detener un Thread temporalmente: Runnable - Not Runnable - Part 3

Se observa que el método sleepf) puede lanzar una InterruptedException que ha de ser capturada. Así se ha hecho en este ejemplo, aunque luego no se gestiona esa excepción.
La forma preferible de detener temporalmente un thread es la utilización conjunta de los métodos waitQ y notifyAllQ. La principal ventaja del método waitQ frente a los métodos anteriormente descritos es que libera el bloqueo del objeto, por lo que el resto de threads que se encuentran esperando para actuar sobre dicho objeto pueden llamar a sus métodos. Hay dos formas de llamar a waitQ: 
1. Indicando el tiempo máximo que debe estar parado (en milisegundos y con la opción de indicar también nanosegundos). de fonna análoga a sleepf). A diferencia del método sleepf). que simplemente detiene el thread el tiempo indicado, el método waitQ establece el tiempo máximo que debe estar parado. Si en ese plazo se ejecutan los métodos notifyf) o notifyAllf) que indican la liberación de los objetos bloqueados, el thread continuará sin esperar a concluir el tiempo indicado. Las dos declaraciones del método waitQ son como siguen:
public final void wait(long timeout) throws InterruptedException
public final void wait(long timeout, int nanos) throws InterruptedException

2. Sin argumentos, en cuyo caso el thread permanece parado hasta que sea reinicializado explícitamente mediante los métodos notifyf) o notifyAllf).
public final void wait() throws InterruptedException

Los métodos waitQ y notifyf) han de estar incluidas en un método synchronized, ya que de otra fonna se obtendrá una excepción del tipo IllegalMonitorStateException en tiempo de ejecución. El uso típico de waitQ es el de esperar a que se cumpla alguna determinada condición, ajena al propio thread. Cuando ésta se cumpla, se utilizará el método notifyAllf) para avisar a los distintos threads que pueden utilizar el objeto. Estos nuevos conceptos se explican con más profundidad en el Apartado 6.3.

lunes, 14 de abril de 2014

Detener un Thread temporalmente: Runnable - Not Runnable - Part 2

Si lo que se desea es parar o bloquear temporalmente un thread (pasar al estado Not Runnable). existen varias formas de hacerlo: 
1. Ejecutando el método sleepf) de la clase Thread. Esto detiene el thread un tiempo pre- establecido. De ordinario el método sleep() se llama desde el método run(). 
2. Ejecutando el método waitf) heredado de la clase Object. a la espera de que suceda algo que es necesario para poder continuar. El thread volverá nuevamente a la situación de runnable mediante los métodos notifyQ o notifyAllQ, que se deberán ejecutar cuando cesa la condición que tiene detenido al thread (ver Apartado 6.3. en la página 131). 
3. Cuando el thread está esperando para realizar operaciones de Entrada Salida o Input Output (E/S ó I/O). 
4. Cuando el thread está tratando de llamar a un método synchronized de un objeto, y dicho objeto está bloqueado por otro thread (véase el Apartado 6.3) 
Un thread pasa automáticamente del estado Not Runnable a Runnable cuando cesa alguna de las condiciones anteriores o cuando se llama a notify() o notifyAUQ.
La clase Thread dispone también de un método stop(). pero no se debe utilizar ya que puede provocar bloqueos del programa (deadlock). Hay una última posibilidad para detener un thread. que consiste en ejecutar el método suspendQ. El thread volverá a ser ejecutable de nuevo ejecutando el método resumef). Esta última fonna también se desaconseja, por razones similares a la utilización del método stop(). 
El método sleepf) de la clase Thread recibe como argumento el tiempo en milisegundos que ha de permanecer detenido. Adicionalmente. se puede incluir un número entero con un tiempo adicional en nanosegnndos. Las declaraciones de estos métodos son las siguientes:

public static void sleep(long millis) throws InterruptedException
public static void sleep(long millis, int nanosecons) throws InterruptedException

Considérese el siguiente ejemplo:
System.out.println ("Contador de segundos");
int count=0;
public void run () {
try {
sleep(lOOO);
System.out.println(count++) ;
} catch (InterruptedException e){}
}

domingo, 13 de abril de 2014

Detener un Thread temporalmente: Runnable - Not Runnable - Part 1

El sistema operativo se ocupa de asignar tiempos de CPU a los distintos threads que se estén ejecutando simultáneamente. Aun en el caso de disponer de un ordenador con más de un procesador (2 ó más CPUs). el número de threads simultáneos suele siempre superar el| número de CPUs. por lo que se debe repartir el tiempo de forma que parezca que todos los procesos corren a la vez (quizás más lentamente), aun cuando sólo unos pocos pueden estar ejecutándose en un instante de tiempo. Los tiempos de CPU que el sistema continuamente asigna a los distintos threads en estado nnntable se utilizan en ejecutar el método ruit() de cada thread. Por diversos motivos, un thread puede en un determinado momento renunciar "voluntariamente" a su tiempo de CPU y otorgárselo al sistema para que se lo asigne a otro thread. 
Esta "renuncia" se realiza mediante el método yieldf). Es importante que este método sea utilizado por las actividades que tienden a "monopolizar" la CPU. El método yieldQ viene a indicar que en ese momento no es muy importante para ese thread el ejecutarse continuamente y por lo tanto tener ocupada la CPU. En caso de que ningún thread esté requiriendo la CPU para una actividad muy intensiva, el sistema volverá casi de inmediato a asignar nuevo tiempo al thread que fue "generoso*' con los demás. Por ejemplo, en un Pentium II 400 Mhz es posible llegar a más de medio millón de llamadas por segundo al método yield(). dentro del método run('), lo que significa que llamar al método yieldf) apenas detiene al thread. sino que sólo ofrece el control de la CPU para que el sistema decida si hay alguna otra tarea que tenga mayor prioridad.

sábado, 12 de abril de 2014

Ejecución de un nuevo thread

La creación de un nuevo thread no implica necesariamente que se empiece a ejecutar algo. Hace falta iniciarlo con el método start(). ya que de otro modo, cuando se intenta ejecutar cualquier método del thread -distinto del método start()- se obtiene en tiempo de ejecución el error IllegalThreadStateException. El método startQ se encarga de llamar al método run() de la clase Thread. Si el nuevo thread se ha creado heredando de la clase Thread la nueva clase deberá redefinirir el método run() heredado. En el caso de utilizar mía clase que implemente la interface Runnable. el método run() de la clase Thread se ocupa de llamar al método run() de la nueva clase (véase el Apartado 6.1.2, en la página 126). 
Una vez que el método startf) ha sido llamado, se puede decir ya que el thread está "corriendo" (running). lo cual no quiere decir que se esté ejecutando en todo momento, pues ese thread tiene que compartir el tiempo de la CPU con los demás threads que también estén running. Por eso más bien se dice que dicha thread es runnable.

viernes, 11 de abril de 2014

CICLO DE VIDA DE UN THREAD

En el apartado anterior se ha visto cómo crear nuevos objetos que permiten incorporar en un programa la posibilidad de realizar varias tareas simultáneamente. En la Figura 6.2 (tomada del Tutorial de Sun) se muestran los distintos [ estados por los que puede pasar un thread a lo largo de su vida. Un thread puede presentar cuatro estados distintos:

  1. Nuevo (New)\ El thread ha sido creado pero no inicializado. es decir, no se ha ejecutado todavía el método start(). Se producirá un mensaje de error (.IllegalThreadStateException) si se intenta ejecutar cualquier método de la clase Thread distinto de start(). 
  2.  Ejecutable (Runnable): El thread puede estar ejecutándose, siempre y cuando se le haya asignado un determinado tiempo de CPU. En la práctica puede no estar siendo ejecutado en un instante determinado en beneficio de otro thread. 
  3. Bloqueado (Blocked o Not Runnable): El thread podría estar ejecutándose, pero hay alguna actividad interna suya que lo impide, como por ejemplo una espera producida pol- lina operación de escritura o lectura de datos por teclado (E/S). Si un thread está en este estado, no se le asigna tiempo de CPU. 
  4. Muerto (Dead): La fonna habitual de que un thread muera es finalizando el método run(). También puede llamarse al método stopf) de la clase Thread. aunque dicho método es considerado '"peligroso" y no se debe utilizar. 
A continuación se explicarán con mayor detenimiento los puntos anteriores. 

jueves, 10 de abril de 2014

Creación de threads derivando de la clase Thread - II

}
// definición del método run()
public void run() {
for(int i=0;i<10;i++)
System.out.println("Este es el thread: " + nameThread);
}
}
El siguiente código crea un nuevo thread y lo ejecuta por este segundo procedimiento:
SimpleRunnable p = new SimpleRunnable("Hilo de prueba");
// se crea un objeto de la clase Thread pasándolo el objeto Runnable como argumento
Thread miThread = new Thread(p);
// se arranca el objeto de la clase Thread
miThread.start();
Este segundo método cobra especial interés con las applets. ya que cualquier applet debe
heredar de la clase java.applet.Applet. y por lo tanto ya no puede heredar de Thread.
Véase el
siguiente ejemplo:
class ThreadRunnable extends Applet implements Runnable {
private Thread runner=null;
// se redefine el método start() de Applet
public void start () {
if (runner == nuil) {
runner = new Thread(this);
runner.start(); // se llama al método start() de Thread
}
}
// se redefine el método stop() de Applet
public void stop(){
runner = nuil; // se libera el objeto runner
}

}
En este ejemplo, el argumento this del constructor de Thread hace referencia al objeto Runnable cuyo método run() debería ser llamado cuando el hilo ejecutado es un objeto de ThreadRunnable. 
La elección de una u otra fonna -derivar de Thread o implementar Runnable- depende del tipo de clase que se vaya a crear. Así. si la clase a utilizar ya hereda de otra clase (por ejemplo mi applet. que siempre hereda de Applet). no quedará más remedio que implementar Runnable. aunque normalmente es más sencillo heredar de Thread.

miércoles, 9 de abril de 2014

Creación de threads derivando de la clase Thread - I

Considérese el siguiente ejemplo de declaración de una nueva clase:
public class SimpleThread extends Thread {
// constructor
public SimpleThread (String str) {
super(str);
}
// redefinición del método run()
public void run() {
for(int i=0;i<10;i++)
System.out.println("Este es el thread : " + getName());
}

}
En este caso, se ha creado la clase SimpleThread. que hereda de Thread. En su constructor se utiliza un String (opcional) para poner nombre al nuevo thread creado, y mediante snper() se llama al constructor de la super-clase Thread. 
Asimismo, se redefine el método run(). que define la principal actividad del thread. para que escriba 10 veces el nombre del thread creado. 
Para poner en marcha este nuevo thread se debe crear un objeto de la clase SimpleThread. y llamar al método start().heredado de la super-clase Thread. que se encarga de llamar a run(). Por ejemplo: SimpleThread miThread = new SimpleThread("Kilo de prueba"); miThread.start();

martes, 8 de abril de 2014

CREACIÓN DE THREADS

En Java hay dos formas de crear nuevos threads. La primera de ellas consiste en crear una nueva clase que herede de la clase java.lang.Thread y sobrecargar el método run() de dicha clase. El segundo método consiste en declarar una clase que implemente la interface java.lang.Runnable. la cual declarará el método runQ; posteriormente se crea un objeto de tipo Thread pasándole como argumento al constructor el objeto creado de la nueva clase (la que iniplementa la interface Runnable). Como ya se ha apuntado, tanto la clase Thread como la interface Runnable pertenecen al package java.lang, por lo que no es necesario importarlas. A continuación se presentan dos ejemplos de creación de threads con cada uno de los dos métodos citados.

lunes, 7 de abril de 2014

THREADS: PROGRAMAS MULTITAREA

Los procesadores y los Sistemas Operativos modernos permiten la multitarea. es decir, la realización simultánea de dos o más actividades (al menos aparentemente). En la realidad, un ordenador con una sola CPU no puede realizar dos actividades a la vez. Sin embargo los Sistemas Operativos actuales son capaces de ejecutar varios programas "simultáneamente" aunque sólo se disponga de una CPU: reparten el tiempo entre dos (o más) actividades, o bien utilizan los tiempos muertos de una actividad (por ejemplo, operaciones de lectura de datos desde el teclado) para trabajar en la otra. 
En ordenadores con dos o más procesadores la multitarea es real, ya que cada procesador puede ejecutar un hilo o thread diferente. La Figura 6.1. tomada del Tutorial de Sun, muestra los esquemas correspondientes a un programa con una o dos threads.
Un proceso es un programa ejecutándose de fonna independiente y con un espacio propio de memoria. Un Sistema Operativo multitarea es capaz de ejecutar más de mi proceso simultáneamente. Un thread o hilo es un flujo secuencial simple dentro de un proceso. Un único proceso puede tener varios hilos ejecutándose. 
Por ejemplo el programa Netscape sería un proceso, mientras que cada una de las ventanas que se pueden tener abiertas simultáneamente trayendo páginas HTML estaría fonnada por al menos un hilo. Un sistema multitarea da realmente la impresión de estar haciendo varias cosas a la vez y eso es una gran ventaja para el usuario. Sin el uso de threads hay tareas que son prácticamente imposibles de ejecutar, particulannente las que tienen tiempos de espera importantes entre etapas. Los threads o hilos de ejecución permiten organizar los recursos del ordenador de fonna que pueda haber varios programas actuando en paralelo. Un hilo de ejecución puede realizar cualquier tarea que pueda realizar un programa nonnal y corriente. Bastará con indicar lo que tiene que hacer en el método run(), que es el que define la actividad principal de las threads. Los threads pueden ser daemon o no daemon. Son daemon aquellos hilos que realizan en background (en un segundo plano) servicios generales, esto es. tareas que no forman paite de la esencia del programa y que se están ejecutando mientras no finalice la aplicación. 
Un thread daemon podría ser por ejemplo aquél que está comprobando permanentemente si el usuario pulsa un botón. Un programa de Jara finaliza cuando sólo quedan corriendo threads de tipo daemon. Por defecto, y si no se indica lo contrario, los threads son del tipo no daemon.

viernes, 4 de abril de 2014

Técnica del doble buffer

La técnica del doble buffer proporciona la mejor solución para el problema de las animaciones, aunque requiere una programación algo más complicada. La idea básica del doble buffer es realizar los dibujos en una imagen invisible, distinta de la que se está viendo en la pantalla, y hacerla visible cuando se ha terminado de dibujar, de fonna que aparezca instantáneamente. 
Para crear el segundo buffer o imagen invisible hay que crear un objeto de la clase Image del mismo tamaño que la imagen que se está viendo y crear un contexto gráfico u objeto de la clase Graphics que permita dibujar sobre la imagen invisible. Esto se hace con las sentencias. Image imglnv; Graphics graphlnv; Dimensión dimlnv; Dimensión d = size(); // se obtiene la dimensión del panel en la clase que controle el dibujo (por ejemplo en una clase que derive de Panel). 
El siguiente paso es re-definir el método updateQ de fonna que no borre la imagen anterior con el color de fondo. Deberá llamar directamente al método paintQ: public void update (Graphics g) { paint(g); // Sin borrar la imagen anterior se llama al método paint() } // fin del método update() En el método paintQ se modifica el código de modo que primero se dibuje en la imagen invisible y luego ésta se haga visible:

public void paint (Graphics g) {
// se comprueba si existe el objeto invisible y si sus dimensiones son correctas
if ((graphlnv==null) II (d.width!=dimlnv.width) II (d.height!=dimlnv.height)) {
dimlnv = d;
// se llama al método createImage de la clase Component
imglnv = createlmage(d.width, d.height);
// se llama al método getGraphics de la clase Image
graphlnv = imglnv.getGraphics();
}
// se establecen las propiedades del contexto gráfico invisible,
// y se dibuja sobre él
graphlnv.setColor(Color.white); // Se borra pintando de blanco
graphlnv.fillRect(0, 0, dimlnv.width, dimlnv.height) ;
graphlnv.setColor(Color.white); // Se asigna un color para dibujar
// Sentencias para dibujar sobre graphlnv
graphlnv.drawLine(0, 0, 100, 100);
// finalmente se hace visible la imagen invisible a partir del punto (0, 0)
//         utilizando el propio panel como ImageObserver
g.drawImage(imglnv, 0, 0, this);
} // fin del método paint()
Los gráficos y las animaciones son particularmente útiles en las applets. El Tutoríal de Sun tiene un ejemplo (un applet) completamente explicado y desarrollado sobre las animaciones y los distintos métodos de eliminar el flicker o paipadeo.

jueves, 3 de abril de 2014

Eliminación del parpadeo o flicker redefiniendo el método update()

El problema del flicker se localiza en la llamada al método updateQ. que borra todo pintando con el color de fondo y después llama a paintQ. Una fonna de resolver esta dificultad es re-definir el método updateQ. de fonna que se adapte mejor al problema que se trata de resolver. Una posibilidad es no re-pintar todo con el color de fondo, no llamar a paintQ e introducir en updateQ el código encargado de realizar los dibujos, cambiando sólo aquello que haya que cambiar. 
A pesar de esto, es necesario re-definir paintQ pues es el método que se llama de fonna automática cuando la ventana de Java es tapada por otra que luego se retira. Una posible solución es hacer que paintQ llame a updateQ, terminando por establecer un orden de llamadas opuesto al de defecto. Hay que tener en cuenta que. al no borrar todo pintando con el color de fondo, el programador tiene que preocuparse de borrar de forma selectiva entre frame y frame lo que sea necesario. Los métodos setClipQ y clipRectQ de la clase Graphics permiten hacer que las operaciones gráficas no surtan efecto fuera de un área rectangular previamente determinada. Al ser dependiente del tipo de gráficos concretos de que se trate, este método no siempre proporciona soluciones adecuadas.

miércoles, 2 de abril de 2014

ANIMACIONES

Las animaciones tienen un gran interés desde diversos puntos de vista. Una imagen vale más que mil palabras y una imagen en movimiento es todavía mucho más útil. Para presentar o describir ciertos conceptos el movimiento animado es fundamental. Además, las animaciones o mejor dicho, la forma de hacer animaciones en Java ilustran mucho la forma en que dicho lenguaje realiza los gráficos. En estos apartados se va a seguir el esquema del Tutorial de Sun sobre el AWT. 
Se pueden hacer animaciones de una fonna muy sencilla: se define el métodopaint() de forma que cada vez que sea llamado dibuje algo diferente de lo que ha dibujado la vez anterior. De todas formas, recuérdese que el programador no llama directamente a este método. El programador llama al método repaintQ, quizás dentro de un bucle while que incluya una llamada al método sleepf) de la clase Thread (ver Capítulo 6. a partir de la página 125). para esperar un cierto número de milisegmidos entre dibujo y dibujo (entre frame y frame, utilizando la terminología de las animaciones). Recuérdese que repaintO llama a updatef) lo antes posible, y que updatef) borra todo redibujando con el color de fondo y llama a paintQ. 
La fonna de proceder descrita da buenos resultados para animaciones muy sencillas, pero produce parpadeo o flicker cuando los gráficos son un poco más complicados. La razón está en el propio proceso descrito anteriormente, combinado con la velocidad de refresco del monitor. La velocidad de refresco vertical de un monitor suele estar entre 60 y 75 herzios. Eso quiere decir que la imagen se actualiza unas 60 ó 75 veces por segundo. Cuando el refresco se realiza después de haber borrado la imagen anterior pintando con el color de fondo y antes de que se termine de dibujar de nuevo toda la imagen, se obtiene una imagen incompleta, que sólo aparecerá terminada en uno de los siguientes pasos de refresco del monitor. Ésta es la causa del flicker. A continuación se verán dos formas de reducirlo o eliminarlo.

martes, 1 de abril de 2014

Imágenes

Java permite incorporar imágenes de tipo GIF y JPEG definidas en ficheros. Se dispone para ello de la clase java.awt.Image. Para cargar una imagen hay que indicar la localización del fichero (URL) y cargarlo mediante los métodos Itu age getlmage(String) o Image getlm age(URL, String). Estos métodos existen en las clases java.awt. Toolkit y java.applet.Applet. 
El argumento de tipo String representa una variable conteniendo el nombre del fichero. Cuando estas imágenes se cargan en applets. para obtener el URL pueden ser útiles las fruiciones getDocumentBase() y getCodeBasef). que devuelven el URL del fichero HTML que llama al applet, y el directorio que contiene el applet (en forma de String). Para cargar una imagen hay que comenzar creando mi objeto Image. y llamar al método getlmagef). pasándole como argumento el URL. Por ejemplo: Image miImagen = getImage(getCodeBase() , "imagen.gif") 
Una vez cargada la imagen, hay que representarla, para lo cual se redefine el método paint() para llamar al método dra>vlmage() de la clase Graphics. Dicho método admite varias formas, aunque casi siempre hay que incluir el nombre del objeto imagen creado, las dimensiones de dicha imagen y un objeto ImageObserver. ImageObsen'er es una interface que declara métodos para observar el estado de la carga y visualización de la imagen. Si se está programando un applet. basta con poner como ImageObsen'er la referencia this. ya que en la mayoría de los casos, la iniplementación de esta iiiterface en la clase Applet proporciona el comportamiento deseado. Para más información sobre dicho método dirigirse a la referencia de la API. La clase Image define ciertas constantes para controlar los algoritmos de cambio de escala: 
SCALE_DEFAULT. SCALE_FAST. SCALE_SMOOTH. 
SCALE_REPLICATE. SCALE_AVERAGE. 
La Tabla 5.35 muestra algunos métodos de la clase Image.