Tema 1 Interfaz Grafica de Usuario
1.1 Creación de interfaz gráfica para usuarios
Una interfaz gráfica de usuario presenta un mecanismo amigable al usuario para interactuar
con una aplicación. Una GUI proporciona a una aplicación una apariencia visual.
Los GUIs se crean a partir de componentes de la GUI. A estos se les conoce también como
controles o widgets en otros lenguajes.
Un componente de la GUI es un objeto con el cual interactúa el usuario con el ratón,
teclado, u otra forma de entrada.
Entrada/Salida simple basada en GUI con JOptionPane
Los cuadros de diálogos son ventanas en las cuales los programas muestran mensajes
importantes al usuario, u obtienen información de este.
La clase JOptionPane de java proporciona cuadros de dialogo preempaquetados para
entrada y salida. Estos diálogos se muestran mediante la invocación de los métodos static
de JOptionPane.
public class Suma{
public static void main ( string [] args ){
String numero1=[Link]("Introduzca un
numero");
}
}
Algunas generalidades
Aunque es posible realizar operaciones de entrada y salida utilizando los diálogos de
JOptionPane, la mayoría de las aplicaciones de GUI requieren interfaces de usuario
personalizadas y mas elaboradas.
A continuación se encuentra una lista de varios componentes de la GUI de Swing que se
utilizan para crear GUIs en Java.
La mayoría de estos son componentes puros de java; están escritos, se manipulan y se
muestran completamente en Java.
Los componentes de GUI de swing nos permiten especificar una apariencia visual uniforme
para una aplicación a traves de todas las plataformas.
1.2 Tipos de eventos
Pueden ocurrir muchos tipos distintos de eventos cuando el usuario interactúa con una GUI.
La información acerca de cualquier evento que ocurre se almacena en un objeto de una
clase que se entiende como AWTEvent.
Estos tipos de eventos se utilizan tanto con componentes de AWT como de Swing. Los tipos
de eventos adicionales son específicos para los componentes de GUI de Swing se declaran
en el paquete de [Link].
Existen tres partes requeridas para el manejo de eventos:
El origen del evento: Es el componente especifico de la GUI con el que interactúa el
usuario.
El objeto del evento: Encapsula información acerca del evento que ocurrió, como una
referencia al origen del evento y cualquier información especifica del evento que pueda
requerir el componente de escucha del evento para que este pueda manejarlo.
Componente de escucha del evento: Recibe una notificación del origen del evento
cunado este ocurre, este escucha el evento y uno de sus métodos se ejecuta en
respuesta al evento. Este recibe un objeto evento cunado se notifica al componente de
escucha acerca del evento, después utiliza el objeto evento para responder al evento.
El modelo de manejo de eventos anteriormente descrito se conoce como modelo de
eventos por delegación ya que el procesamiento de un objeto se delega a un objeto
especifico en la aplicación.
Para cada tipo de objeto evento hay, por lo general, una interfaz de escucha de eventos que
le corresponde.
Un componente de escucha de eventos para un evento de GUI es un objeto de una clase
que implementa a una o mas de las interfaces de escucha de eventos de los paquetes AWT
o Swing.
Cada interfaz escucha de eventos especifica uno o mas métodos manejadores de eventos
que deben declararse en la clase que implementa a la interfaz.
Por ejemplo cuando el usuario oprime la tecla intro en un objeto JTextField, se hace una
llamada al método actionPerformed del componente de escucha registrado.
Algunas clases de eventos del paquete [Link]
Algunas interfaces comunes de componentes de escucha de eventos del paquete
[Link]
1.3 Manejo de eventos
¿Cómo se registra el manejador de eventos?
public class campoTexto extends JFrame {
private JTextField campoTexto1;
public campoTexto(){
super("Prueba de JTextField");
setLayout(new FlowLayout());
campoTexto1 =new JTextField("Texto uno");
add(campoTexto1);
ManejadorCampoTexto manejador = new ManejadorCampoTexto();
[Link](manejador);
}
private class ManejadorCampoTexto implements ActionListener{
@Override
public void actionPerformed(ActionEvent evento) {
String cadena="";
if ( [Link]() == campoTexto1 )
cadena = [Link]( "campoTexto1: %s"
,[Link]() );
/*El %s es una manera de insertar el texto a formatear
por ejemplo ahi se agrega el texto obtenido del ActionCommand
que extrae el String que diferencia al botón, menu, etc.*/
[Link](null,cadena);
}
}
public static void main(String[] args) {
campoTexto main = new campoTexto();
[Link](JFrame.EXIT_ON_CLOSE);
[Link](350,100);
[Link](true);
}
}
Aquí el manejador de eventos se registra en las línea 9
[Link]( manejador );
Registro de eventos
Todo JComponent tiene una variable de instancia llamada listenerList, que hace referencia a
un objeto de la clase EventListenerList. Cada objeto de una subclase de JComponent
mantiene referencias a todos sus componentes de escucha registrados en listenerList.
Cuando se ejecuta la linea se coloca en el objeto listenerList de campoTexto1 una nueva
entrada que contiene una referencia la objeto ManejadorCampoTexto. Esta nueva entrada
también incluye el tipo del componente que escucha (ActionListener).
Invocación del manejador de eventos
¿Como sabe el componente de la GUI que debe llamar a actionPerformed en vez de llamar
a otro?
Todo componente de la GUI soporta varios tipos de eventos, incluyendo eventos de ratón,
tecla, etc.
Cuando ocurra un evento, este se despacha solamente a los componentes de escucha de
eventos del tipo apropiado. El despachamiento es simplemente el proceso por el cual el
componente de la GUI llama a un método manejador de eventos en cada uno de sus
componentes de escucha registrados para el tipo de evento que ocurrió.
Cada tipo de evento tiene una o mas interfaces de escucha de eventos correspondientes.
Por ejemplo, los eventos tipo ActionEvent son manejados por objetos ActionListener.
Cuando ocurre un evento, el componente de la GUI recibe un ID de evento único, el cual
especifica el tipo de evento. El componente de la GUI utiliza el ID de evento para decidir a
cual tipo de componente de escucha debe despacharle el evento, y para decidir cual
método llamar en cada objeto de escucha,
Para un ActionEvent, el evento se despacha al método actionPerformed de todos los
objetos ActionListener registrados.
1.4 Manejo de componentes gráficos
Los componentes gráficos de control son elementos de la IGU que permiten al usuario
interactuar con la aplicación. Algunos ejemplo comunes son:
JButton
Un botón es un componente en el que el usuario hace clic para desencadenar cierta acción.
Existen distintos tipos de botón, como botones de comando, casillas de verificaciones,
botones interruptores y botones de opción.
Todos los tipos de botones son subclases de AbstractButton, la cual declara las
características comunes para los botones de Swing.
Un botón de comando genera un evento ActionEvent cuando el usuario hacen clic en el.
Estos se crean con la clase JButton.
Un objeto JButton puede mostrar un objeto Icon, para proveer al usuario un nivel adicional
de interacción visual, un objeto JButton puede tener también un Icon de sustitución, este se
mostrara cuando el usuario coloque el ratón encima de el.
Botones que mantienen el estado
Los componentes de GUI de Swing contienen tres tipos de botones de estado:
JToggleButton, JCheckBox y JRadioButton, los cuales tienen valores encendido/apagado o
verdadero/falso. Las clases JCheckBox y JRadioButton son subclases de JToggleButton.
Un objeto JRadioButton es distinto de un objeto JCheckBox en cuanto a que generalmente
hay varios objetos JRadioButton que se agrupan, y son mutuamente exclusivos; sólo uno de
los objetos JRadioButton en el grupo puede estar seleccionado en un momento dado, de
igual forma que los botones en la radio de un automóvil.
A continuación se mencionan algunos otros componentes gráficos y algunas de sus
características:
JComboBox
Un objeto JComboBox proporciona una lista de elementos, de los cuales el usuario
puede seleccionar uno. Los objetos JComboBox generan eventos ItemEvent.
Cada elemento en un objeto JComboBox tiene un índice. El primer elemento que se
agrega a un objeto JComboBox aparece como el elemento actualmente seleccionado
cuando se muestra el objeto JComboBox. Los otros elementos se seleccionan
haciendo clic en el objeto JComboBox, el cual se expande en una lista, de la cual el
usuario puede seleccionar un elemento.
El método setMaximumRowCount de JComboBox establece el máximo número de
elementos a mostrar cuando el usuario haga clic en el objeto JComboBox. Si hay
elementos adicionales, el objeto JComboBox proporciona una barra de desplazamiento
que permite al usuario desplazarse por todos los elementos en la lista.
Una clase interna anónima es una forma especial de clase interna, que se declara sin
un nombre y por lo general aparece dentro de la declaración de un método. Como una
clase interna anónima no tiene nombre, un objeto de la clase interna anónima debe
crearse en el punto en el que se declara la clase.
El método getSelectedIndex de JcomboBox devuelve el índice del elemento
seleccionado.
JList
Un objeto JList muestra una serie de elementos, de los cuales el usuario puede
seleccionar uno o más. La clase JList soporta las listas de selección simple y de
selección múltiple.
Cuando el usuario hace clic en un elemento de un objeto JList, se produce un evento
ListSelectionEvent. El método addListSelectionListener registra un objeto
ListSelectionListener para los eventos de selección de un objeto JList. Un objeto
ListSelectionListener (paquete [Link]) debe implementar el método
valueChanged.
El método setVisibleRowCount de JList especifica el número de elementos visibles en
la lista.
El método setSelectionMode de JList especifica el modo de selección de una lista.
Un objeto JList no proporciona una barra de desplazamiento si hay más elementos en
la lista que el número de fi las visibles. En este caso, puede usarse un objeto
JScrollPane para proporcionar la capacidad de desplazamiento. El método
getContentPane de JFrame devuelve una referencia al panel de contenido de JFrame,
en donde se muestran los componentes de la GUI.
El método getSelectedIndex de JList devuelve el índice del elemento seleccionado.
Listas de selección multiple
Una lista de selección múltiple permite al usuario seleccionar muchos elementos de un
objeto JList.
El método setFixedCellWidth de JList establece la anchura de un objeto JList. El
método setFixedCellHeight establece la altura de cada elemento en un objeto JList.
No hay eventos para indicar que un usuario ha realizado varias selecciones en una
lista de selección múltiple. Por lo general, un evento externo generado por otro
componente de la GUI especifica cuándo deben procesarse las selecciones múltiples
en un objeto JList.
El método setListData de JList establece los elementos a mostrar en un objeto JList. El
método getSelectedValues de JList devuelve un arreglo de objetos Object que
representan los elementos seleccionados en un objeto JList
JTextArea
Un objeto JTextArea proporciona un área para manipular varias líneas de texto.
JTextArea es una subclase de JTextComponent, la cual declara métodos comunes
para objetos JTextField, JTextArea y varios otros componentes de GUI basados en
texto.
La clase Box es una subclase de Container que utiliza un administrador de esquemas
BoxLayout para ordenar los componentes de la GUI, ya sea en forma horizontal o
vertical.
El método static createHorizontalBox de Box crea un objeto Box que ordena los
componentes de izquierda a derecha, en el orden en el que se adjuntan.
El método getSelectedText (que hereda JTextArea de JTextComponent) devuelve el
texto seleccionado de un objeto JTextArea.
Podemos establecer las políticas de las barras de desplazamiento horizontal y vertical
de un objeto JScrollPane al momento de crearlo. Los métodos
setHorizontalScrollBarPolicy y setVerticalScrollBarPolicy de JScrollPane pueden
usarse para modificar las políticas de las barras de desplazamiento en cualquier
momento.
Tema 2 Componentes y librerías
2.1 Definición conceptual de componentes, paquetes /
librerías
Componente. Un componente es el elemento básico de una interfaz gráfica. Estos permiten
al usuario interactuar con la aplicación y proporcionar información desde el programa al
usuario sobre el estado de aplicación.
Ejemplo: botones, barras de desplazamiento, etiquetas, etc.
Los componentes nunca se encuentran de forma aislada, sino agrupados dentro de
contenedores. Los contenedores contienen y organizan la situación de los componentes,
además de ser en si mismo componentes también.
Paquetes: son una manera de organizar nuestras clases, ya sea por finalidad, por su
relación con la herencia que tienen, etc.
Pasos para crear o utilizar paquetes (package):
1. Crear una carpeta – paquete.
2. Mover y/o almacenar las clases que solucionan el problema.
3. A cada una de las clases, se les agrega la palabra reservada “package” de la siguiente
forma: package NombreDeLaCarpeta;
4. Las clases deben llevar el modificador “public”, por ejemplo: public class Numero.
5. A las clases que utilicen las clases empaquetadas, se les indica la ruta de las clases
correspondientes, ocupando la palabra reservada “import”. import
NombreDeLaCarpeta.*
Librerías
La utilización de objetos dinámicos supone dejar pendiente en el montaje de la aplicación el
enlace de dichos objetos. Cuando la aplicación está en ejecución, y sólo entonces, se
produce el enlace (dinámico) con los objetos contenidos en la librería.
La creación de librerías dinámicas corre a cargo del enlazador o montador (en nuestro caso
el ld) aunque también es posible indicar al compilador las opciones necesarias para el
montaje y de ese modo, será él quien se encargue de pasárselas al montador.
Cuando se crea un objeto dinámico es necesario que dicho código objeto sea independiente
de la posición, para conseguir este tipo de código debe especificarse al compilador la opción
-fPIC (Position IndependentCode). Dicho flag debe indicarse tanto en la compilación como
en el montaje de la librería. Para montar los objetos es necesario además indicar la opción -
shared para que el resultado sea un fichero objeto ‘compartible’.
2.2 Uso de librerías proporcionadas por el lenguaje
Java contiene muchas clases predefinidas que se agrupan en categorías relacionadas
llamadas paquetes (en este caso, java, se les llama Interfaz de programación de
aplicaciones de JAVA o API de java).
Las declaraciones import especifican las clases requeridas para compilar un programa en
java, por ejemplo: import [Link] .
La anterior linea especifica que el programa utiliza la clase Scanner del paquete [Link].
Uno de los puntos mas fuertes de Java es el extenso numero de clases en los paquetes de
la API de java.
Algunas de los paquetes integrados en java son los siguientes:
Para localizar información adicional acerca de los métodos de una clase predefinida de Java
en la documentación para la API de Java en: [Link]
2.3 Creación de componentes (visuales y no
visuales) definidos por el usuario
Componentes visuales y no visuales
Se pueden establecer muchas clasificaciones para los componentes. Una de ellas es la de
visuales o controles, frente a no visuales.
Un componente es visual cuando tiene una representación gráfica en tiempo de diseño y
ejecución, como lo son los botones, cuadros de edición, etc.
Se dice no visual en caso contrario, como temporizadores, cuadros de dialogo, etc.
Los componentes visuales los podemos dividir a su vez en dos tipo:
Componentes interactivos: Permiten que el usuario final los manipule, ya sea
introduciendo datos, seleccionando elementos, etc. De forma que estos componentes
pueden recibir el foco, asi como eventos propios del teclado y ratón.
Componentes gráficos: El propio componente es el encargado de dibujar en la pantalla
lo crea oportuno, bien a traves de las funciones básicas del API de windows, o a traves
de otras librerías gráficas.
Dado que un componente es un objeto como otro cualquiera, podremos aplicar en el todas
las técnicas de la orientación a objetos: encapsulación, herencia y polimorfismo.
La encapsulación simplemente definiendo ciertos atributos como privados, para que no
puedan ser accedidos desde fuera de la clase, y otros públicos o publicados para ser
usados por el programador que utilice el componente.
La herencia nos permite reutilizar código, haciendo que una clase dada (que llamaremos
clase hija) adquirida a todos los atributos y métodos públicos y protegidos de otra, llamada
clase padre. De este método, podemos aprovechar mucho código escrito, simplemente
heredando de una clase ya escrita. Por si fuera poco, también es posible que una clase hijo
tenga a su vez mas descendencia, adquiriendo estos las características del padre y del
"padre del padre", es decir: del abuelo.
La técnica de la herencia aplicada a los componentes, nos permite personalizar cualquier
componente, o porque queremos ampliar las posibilidades del componente.
2.4 Creación y uso de paquetes/librerías definidas
por el usuario.
Definir un paquete:
Todas las clases de Java pertenecen a algún paquete. Cuando no se especifica la
declaración package se usa el paquete predeterminado.
Aunque el paquete predeterminado es valido para programas de pruebas cortos, es
inadecuado para aplicaciones reales.
Para crear un paquete, colocamos el comando package en la parte superior del archivo
fuente de java.
Las clases declaradas dentro de ese archivo pertenecerán al paquete especificado.
Ejemplo de la definición de un paquete package Project1; .
Java usa el sistema de archivo para manejar los paquetes con cada paquete almacenado
en su propio directorio. Por ejemplo, los archivos .class para las clases que se declaren,
para que estos formen parte del paquete deben guardarse en un directorio llamado Project1.
Tema 3 Programación Concurrente
3.1 Concepto de hilo
Los hilos o threads son básicamente, pequeños procesos o piezas independientes de un
gran proceso. También podemos decir, que un hilo es un flujo único de ejecución dentro de
un proceso.
Un hilo no puede correr por si mismo, se ejecuta dentro de un programa, ya que requiere la
supervisión de un proceso padre para correr.
Se pueden programar múltiples hilos de ejecución para que corran simultáneamente en el
mismo programa.
Por ejemplo, un navegador web puede descargar un archivo de un sitio, y acceder a otro
sitio al mismo tiempo. Si el navegador puede realizar simultáneamente dos tareas, no tendrá
que esperar hasta que el archivo haya terminado de descargar para poder navegar a otro
sitio.
Desde el punto de vista de las aplicaciones los hilos son útiles porque permiten que el flujo
del programa sea divido en dos o mas partes, cada una ocupándose de alguna tarea de
forma independiente.
Algunos conceptos a considerar
En equipos con menos procesadores que hilos o thread lanzados en un momento
dado, se habla de concurrencia aparente, ya que todos los hilos no pueden estar
ejecutándose a la vez.
Un exceso de threads o hilos resulta negativo ya que se puede perder mas tiempo
saltando de un thread a otro que en la ejecución real. Esta operación se llama
conmutación de contexto e implica salvar y recuperar datos y registros de memoria.
3.2 Comparación de un programa de flujo único
contra uno de flujo múltiple
Un programa de flujo único o mono hilo utiliza un único flujo de control para controlar su
ejecución. Muchos programas no necesitan la potencia o utilidad de múltiples tareas.
Por ejemplo, imprimir solamente Hola mundo en la consola de java ocurre dentro de una
única tarea.
Mientras que los programas de flujo múltiple, la utilización de los hilos en java permite que
se puedan implementar muy poderosas y portables aplicaciones, por ejemplo, el caso de un
navegador que puede desplazar la pagina mientras un applet continua ejecutándose.
3.3 Creación y control de hilos
Java pone las primitivas de concurrencia a disposición del programador de aplicaciones, a
través del lenguaje y de las APIs.
El programador especifica que una aplicación contiene subprocesos de ejecución
separados, en donde cada subproceso tiene su propia pila de llamadas a métodos y su
propio contador, lo cual le permite ejecutarse concurrentemente con otros subprocesos, al
mismo tiempo que comparte los recursos a nivel de aplicación en otros subprocesos. Esta
capacidad, llamada Subprocesamiento múltiple.
Por ejemplo, cunado se descarga un archivo extenso como una imagen, un clip de audio
o video a través de internet, tal vez el usuario no quiera esperar hasta que se descargue
todo un clip completo para empezar a reproducirlo. Para resolver este problema
podemos poner varios subprocesos a trabajar, uno para el clip y otro para reproducirlo.
Estas actividades se llevan a cabo concurrentemente. Para evitar que la reproducción
del clip tenga interrupciones, sincronizamos los subprocesos de manera que el
subproceso de reproducción no empiece sino hasta que haya una cantidad suficiente del
clip en memoria, como para mantener ocupado el subproceso de reproducción.
Estados de los subprocesos: ciclo de vida de un subproceso
En cualquier momento dado, se dice que un subproceso se encuentra en uno de varios
estados de subproceso.
Un nuevo subproceso empieza su ciclo cuando hace la transición al estado nuevo.
Permanece en este estado hasta que el programa inicia el subproceso, con lo cual se
coloca el en el estado ejecutable.
Se considera que un subproceso en el estado ejecutable esta ejecutando su tarea.
Algunas veces un subproceso ejecutable cambia al estado en espera mientras espera
a que otro subproceso realice una tarea. Un subproceso en espera regresa al estado
ejecutable solo cuando un subproceso notifica al subproceso esperando que puede
continuar ejecutándose.
Un subproceso ejecutable puede entrar al estado en espera sincronizado durante un
intervalo especifico de tiempo. Regresa al estado ejecutable cuando ese intervalo de
tiempo expira, o cunado ocurre el evento que esta esperando.
Los subprocesos en espera sincronizada y en espera no pueden usar un procesador,
aun cunado haya uno disponible.
Un subproceso ejecutable puede cambiar al estado en espera sincronizado si
proporciona un intervalo de espera opcional cuando esta esperando a que otro
subproceso realice su tarea. Dicho subproceso regresa al estado ejecutable cuando se
le notifica otro subproceso, o cunado expira el intervalo de tiempo.
Otra manera de colocar un subproceso en el estado de espera sincronizado es dejar
inactivo un subproceso ejecutable. Un subproceso inactivo permanece en el estado en
espera sincronizado durante un periodo designado de tiempo (conocido como intervalo
de inactividad), después del cual regresa al estado ejecutable.
Los subprocesos estas inactivos, cuando en ciertos momentos no tienen una tarea que
realizar.
Un subproceso ejecutable cambia al estado bloqueado cuando trata de realizar una
tarea que no puede completarse inmediatamente, y debe esperar temporalmente hasta
que se complete esa tarea.
Por ejemplo cuando un subproceso emite una petición de estrada/salida, el sistema
operativo bloquea el subproceso para que no se ejecute si no hasta que se complete la
petición de E/S; en ese punto el subproceso bloqueado cambia el estado de ejecutable
para continuar con su ejecución.
Un subproceso bloqueado no puede usar un procesador, aun si hay uno disponible.
Un subproceso ejecutable entra al estado de terminado o muerto, cuando completa
exitosamente su tarea, o termina de alguna forma (debido a algún error).
Prioridades y programación de subprocesos
Todo subproceso en java tiene una prioridad de subproceso, la cual ayuda al sistema
operativo a determinar el orden en el que se programan los subprocesos.
Las prioridades en Java varían entre MIN_PRIORITY (Constante de 1) y MAX_PRIORITY
(Constante de 10).
De manera predeterminada cada subproceso recibe la prioridad de NORM_PRIORITY
(Constante de 5).
Cada subproceso hereda la prioridad del subproceso que lo creo.
Se recomienda no crear y usar explícitamente objetos Thread para implementar la
concurrencia, si no utilizar mejor la interfaz Executor.
La mayoría de SO soportan intervalos de tiempo que permiten a los subprocesos de igual
prioridad compartir un [Link] este, cada subproceso en un conjunto de
subprocesos de igual prioridad se ejecuta hasta completarse antes que otros subprocesos
de igual prioridad tengan oportunidad de ejecutarse.
Con este tiempo, aun si un subproceso no ha terminado de ejecutarse, cunado expira su
tiempo, el procesador se quita del subproceso y pasa al siguiente subproceso de igual
prioridad, eso si hay alguno disponible.
El programador de subprocesos de un sistema operativo determina cual subproceso se
debe ejecutar a continuación. Una implementación simple del programador de subprocesos
mantiene el subproceso de mayor prioridad en ejecución en todo momento, y si hay mas de
un subproceso de mayor prioridad, asegura que esos subprocesos se ejecuten durante un
quantum cada uno en forma cíclica.
Cuando un subproceso de mayor prioridad entra al estado listo, el SO generalmente
sustituye el subproceso actual en ejecución para dar preferencia al subproceso de mayor
prioridad (Programación preferente).
Creación y ejecución de subprocesos
El medio preferido de crear aplicaciones con subprocesos multiples es mediante la
implementación de la interfaz Runnable. Un objeto de esta clase representa una tarea que
puede ejecutarse concurrentemente con otras tareas.
La interfaz declara solo un método, run, el cual contiene el código que define la tarea que
debe realizar el objeto.
Cuando se crea e inicia un subproceso que ejecuta un objeto runnable, el subproceso llama
al método run del objeto Runnable, el cual ejecuta el nuevo subproceso.
public class TareaImprimir implements Runnable {
private final String nombre;
public TareaImprimir(String nombre) {
[Link] = nombre;
}
@Override
public void run() {
for(int i=0;i<10;i++)
[Link](i+" "+nombre);
[Link]("Termina thread"+ nombre);
}
public static void main(String[] args) {
[Link]("Creacion de subprocesos");
Thread subproceso1= new Thread(new TareaImprimir("Pepe"));
Thread subproceso2= new Thread(new TareaImprimir("Juan"));
[Link]();
[Link]();
}
}
Observase en la salida el primer mensaje de finalización del thread main. La ejecución
de los hilos es asíncrona. Realizada la llamada al método start(), éste le devuelve
control y continua su ejecución, independiente de los otros hilos.
En la salida los mensajes de un hilo y otro se van mezclando. La máquina virtual
asigna tiempos a cada hilo.
3.4 Sincronización de hilos de computación
Cuando varios subprocesos comparten un objeto, y este puede ser modificado por uno o
mas de los subprocesos, pueden ocurrir resultados indeterminados, a menos que el acceso
al objeto compartido se administre de manera apropiada.
Por ejemplo, si un subproceso va a actualizar un objeto compartido, y otro subproceso trata
de actualizarlo también, no queda claro cual actualización se lleva a cabo. A veces actúa de
una forma, aveces de otra.
El problema se puede resolver si se da a un subproceso a la vez el acceso exclusivo al
código, es decir que otro subproceso al querer manipular el objeto debe mantenerse en
espera hasta que el subproceso en acceso exclusivo termine.
Los ejemplos anteriores muestran como un programa ejecuta varios hilos de forma
asíncrona. Una vez iniciado cada hilo vive de forma independiente de los otros, no existe
ninguna relación entre ellos, ni tampoco ningún conflicto, pero, hay ocasiones que distintos
hilos si se necesitan entre si.
Se necesita compartir entonces algún mecanismo que permita sincronizar hilos, asi como,
establecer reglas para acceder a los recursos compartidos.
Un ejemplo típico en que dos procesos necesitan sincronizarse es el caso en que un hilo
produzca algún tipo de información que es procesada por otro hilo.
Una manera de realizar la sincronización es mediante los monitores integrados en Java.
Cada objeto tiene un monitor y un bloqueo de monitor. El monitor asegura que el bloqueo de
monitor de su objeto se mantenga por un máximo de solo un subproceso a la vez. Si una
operación requiere que el subproceso en ejecución mantenga un bloqueo mientras se
realiza la operación, un subproceso debe adquirir el bloqueo para poder continuar con la
operación. Otros subprocesos que traten de realizar una operación que requiera el mismo
bloqueo permanecerán bloqueados hasta que el primer subproceso libere el bloqueo, punto
en el cual los subprocesos bloqueados pueden tratar de adquirir el bloqueo y continuar con
las operaciones.
Para especificar que un subproceso debe mantener un bloqueo de monitor para ejecutar un
bloqueo, debe colocarse una instrucción synchronized.
Se dice que dicho código esta protegido por el bloqueo de monitor
Las instrucciones synchronized se declaran mediante la palabra clave synchronized.
synchronized ( objeto){
instrucciones
}
En donde objeto es el objeto cuyo bloqueo de monitor se va a adquirir.
Referencias y Fuentes:
Deitel, D. y. (2010). Java Cómo Programar. México: Prentice Hall.
[Link]
[Link]
[Link]
Unidad 4 Acceso a Datos
4.1 Introducción
Una base de datos es una colección organizada de datos.
Un sistema de administración de base de datos proporciona los mecanismos, pero almacenar,
organizar, obtener y modificar datos para muchos usuarios. Los sistemas de administración de
bases de datos permiten el acceso y almacenamiento de datos sin necesidad de preocuparse
por su representación interna.
Un lenguaje llamado SQL es el lenguaje estándar internacional que se utiliza casi
universalmente con las bases de datos relacionales para realizar consultas y manipular datos.
Los programas en Java se comunican con las bases de datos y manipulan sus datos utilizando
la API JDBC. Un controlador de JDBC permite a las aplicaciones de Java conectarse a una
base de datos en un DBMS especifico, y nos permite manipular esa base de datos mediante la
API JDBC.
4.2 Conexión a origen de datos
El siguiente programa muestra como conectarse a la base de datos, hacer una consulta en la
misma y procesar el resultado.
En las primeras líneas de import se importan las interfaces de JDBC y las clases del paquete
de [Link] que se utilizan.
Primero se declara una constante cadena para el controlador de la base de datos y después se
declara una cadena para el URL de la base de datos. Estas constantes identifican el nombre de
la base de datos a la que nos conectaremos, así como la información acerca del protocolo
utilizado por el controlador JDBC.
En este caso el programa se conectaría a una base de datos llamada libros, donde realiza una
consulta, muestra el resultado y después cierra la conexión a la base de datos.
El programa debe cargar el controlador de base de datos para poder conectarse con la base de
datos.
La línea que contiene el [Link] se utiliza para cargar la clase para el controlador de
bases de datos. Para evitar excepciones al no localizar la clase del controlador necesitamos
incluir el archivo mysql-connector-java-(version)-[Link] en la ruta de clases del programa a la
hora de ejecutarlo.
java –classpath
.;c:\mysql-connector-java-5.0.4\[Link]
MostrarAutores
También se puede copiar el archivo al directorio de java.
Después creamos un objeto Connection, el cual le pusimos el nombre de conexión. Este objeto
que implementa la interfaz Connection administra la conexión entre el programa de java y la
base de datos. Los objetos Connection permiten a los programas crear instrucciones de SQL
para manipular la base de datos. El programa inicializa a conexión con el resultado de una
llamada al método getConecction de la clase DriverManager, el cual trata de conectarse a la
base de datos especificada mediante su URL.
El método getConnection recibe tres argumentos: un objeto String que especifica el URL de la
base de datos, un objeto String que especifica el nombre de usuario y un objeto String que
especifica la contraseña.
Se invoca el método createStatement para obtener un objeto que implemente la interfaz
Statement. El programa utiliza al objeto Statement para enviar instrucciones de SQL a la base
de datos.
El método executeQuery del objeto Statement se utiliza para enviar una consulta que
seleccione toda la información sobre los autores en la tabla de autores. Este método devuelve
un objeto que implementa la interfaz ResultSet, y contiene el resultado de esta consulta.
Los métodos de ResultSet permiten al programa manipular el resultado de la consulta.
A continuación, se procesa el objeto ResultSet, primero se obtienen los metadatos para el
objeto ResultSet en forma de un objeto ResultSetMetaData.
Los metadatos describen el contenido del objeto ResultSet. Los programas pueden usar
metadatos mediante la programación, para obtener información acerca de los nombres y tipos
de las columnas del objeto ResultSet. Por ejemplo, se utiliza el método getColumnCount para
obtener el numero de columnas para el objeto ResultSet.
Para mostrar los resultados, primero el programa posiciona el cursor de ResultSet (Este apunta
a la fila que se esta procesando) en la primera fila en el objeto ResultSet, mediante el método
next. Este método devuelve el valor boolean true si el curso puede posicionarse en la siguiente
fila, en caso contrario el método devuelve false.
El bloque finally cierra los objetos ResultSet, Statement y el objeto Conecction de la base de
datos.
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
public class MostrarAutores{
//NOMBRE DEL CONTROLADOR DE JDBC Y URL DE LA BASE DE DATOS
static final String CONTROLADOR = "[Link]";
static final String URL_BASEDATOS = "jdbc:myswl://localhost/libros";
public static void main(String[]Args){
//MANEJA LA CONEXION
Connection conexion = null;
//INSTRUCCION DE CONSULTA
Statement instruccion = null;
//MANEJA LOS RESULTADOS
ResultSet conjuntoResultados = null;
//SE CONECTA A LA BASE DE DATOS Y REALIZA UNA CONSULTA
try{
//CARGA LA CLASE CONTROLADOR
[Link]( CONTROLADOR );
//ESTABLECE LA CONEXION CON LA BASE DE DATOS
conexion = [Link](URL_BASEDATOS, "jhtp7",
"jhtp7");
//CREA OBJETO STATEMENT PARA CONSULTAR LA BASE DE DATOS
instruccion = [Link]();
//CONSULTA LA BASE DE DATOS
conjuntoResultados = [Link](
"SELECT IdAutor, nombrePila, apellidoPaterno FROM autores"
);
//PROCESA LOS RESULTADOS DE LA BASE DE DATOS
ResultSetMetaData metaDatos = [Link]();
int numeroDeColumnas = [Link]();
[Link]("Tabla Autores de la base de datos Libros:");
for( int i=1; i<=numeroDeColumnas; i++ )
[Link]("%-8s\t", [Link]( i ) );
[Link]();
while ( [Link]() )
{
for ( int i = 1; i <= numeroDeColumnas; i++ )
[Link]( "%-8s\t", [Link]( i ) );
[Link]();
}
}
catch( SQLException excepcionSQL ){
[Link]();
}
catch( ClassNotFoundException noEncontroClase ){
[Link]();
}
finally{
try{
[Link]();
[Link]();
[Link]();
}
catch( Exception excepcion ){
[Link]();
}
4.3 Manipulación de datos
Manipulación de datos con la interfaz RowSet
La interfaz Rowset, configura la conexión a la base de datos y prepara instrucciones de consulta de forma
automática, además, proporciona varios métodos para establecer que nos permiten especificar las
propiedades necesarias para establecer una conexión y crear un objeto Statement.
Hay dos tipos de objetos RowSet:
• Conectado: se conecta a la base de datos una sola vez, y permanece conectado hasta que
termina la aplicación.
• Desconectado: Se conecta a la base de datos ejecuta una consulta para obtener los datos de la
base de datos y después cierra la conexión.
Un programa puede cambiar los datos de un objeto RowSet desconectado, mientras este se encuentre
desconectado. Los datos modificados se pueden actualizar en la base de datos después de que el objeto
RowSet restablezca la conexión con la base de datos.
Ejemplo de conexión con RowSet
//IMPORTS
public class PruebaJdbcRowSet{
//controlador JDBC y URL
static final String CONTROLADOR = "[Link]";
static final String URL_BASEDATOS = "jdbc:mysql://localhost/libros";
static final String NOMBREUSUARIO = "jhtp7";
static final String CONTRASENIA = "jhtp7";
public PruebaJdbcRowSet(){
try{
[Link](CONTROLADOR);
//PROPIEDADES DEL OBJETO JdbRowSet
JdbRowSet rowSet = new JdbRowSet();
[Link](URL_BASEDATOS);
[Link](NOMBREUSUARIO);
[Link](CONTRASENIA);
//ESTABLECE LA CONSULTA Y LA EJECUTA
[Link]("SELECT*FROM autores");
[Link]();
//PROCESA LOS RESULTADOS DE LA CONSULTA
ResultSetMetaData metaDatos = [Link]();
int numeroDeColumnas = [Link]();
[Link]( "Tabla Autores de la base de datos Libros:\n" );
//MUESTRA ENCABEZADOS
for( int i=1;i<=numeroDeColumnas; i++ )
[Link]( "%-8s\t", [Link]( i ) )
[Link]();
//MUESTRA FILAS
while([Link]()){
for( int i=1;i<=numeroDeColumnas;i++ )
[Link]( "%-8s\t", [Link]( i ) );
[Link]();
}
[Link]()
}
catch(){
//TODO LO DE CERRAR ERRORES Y ASI
}
}
}
Ejemplo de CachedRowSet para almacenar en cache y cambiar las filas.
// CONECTAR A LA BASE DE DATOS
CachedRowSet crs = [Link]();
[Link]("jdbc:mysql://localhost/test");
[Link]("root");
[Link]("root");
[Link]("SELECT * FROM user");
[Link]();
// ESTE TIPO DE OPERACION SOLO PUEDE CAMBIAR EL ROWSET INDEPENDIENTE
// PRIMERO MUEVE EL PUNTERO A UNA CADENA VACIA
[Link]();
[Link](1, [Link]());
[Link](2, "Clone" + [Link]());
[Link](3, "Female");
// SE AGREGA LA NUEVA LINEA AL RESTO DE LAS OTRAS LINEAS
[Link]();
// SE REGRESA EL PUNTERO A LA FILA DONDE SE ENCONTRABA ANTES DE LA INSERCION
[Link](); /
[Link]();
while([Link]()) {
[Link]([Link](1) + "," + [Link](2) + "," +
[Link](3));
}
// SE SUBEN TODAS LAS ACTUALIZACIONES A LA BASE DE DATOS
Connection con = [Link]("jdbc:mysql://localhost/dbtest",
"root", "root");
[Link](false);
[Link](con);
también se puede hacer la manipulación de datos con objetos PreparedStatement
4.4 Visualización de datos
Visualizar datos de una base de datos de forma grafica es una parte fundamental en muchos
sistemas, ya que proporciona una manera intuitiva de entender y analizar la información
almacenada. En Java, existen diferentes herramientas y bibliotecas que ayuda a hacer esto.
Algunas de las mas comunes son JavaFX o Swing que proporcionan componentes gráficos que
pueden utilizarse para crear interfaces de usuario interactivas y más visuales.
Por ejemplo, se pueden utilizar tablas para mostrar datos tabulares, gráficos de barras o
circulares para representar datos estadístos.