Todas las entradas de: Antonio Archilla

OCP7 11 – Hilos (01) – Introducción

 

En este apartado se exponen los conceptos básicos referentes del diseño de programas concurrentes y paralelos y los mecanismos que la especificación estándar de Java pone a disposición del programador para conseguirlo.

 
Se tratarán los siguientes conceptos:

 

  • Cómo el sistema operativo gestiona los procesos e hilos.
  • Ciclo de vida de un hilo de ejecución.
  • Sincronización y comunicación de datos entre hilos de ejecución.

 

Gestión de procesos e hilos

La Multitarea se describe cómo la habilidad de ejecutar varias tareas aparentemente al mismo tiempo compartiendo uno o varios procesadores. 
Existen dos tipos de tareas:
  • Procesos: Conjunto de instrucciones de código que se ejecutan secuencialmente y que tiene asociados un estado y recursos de sistema (espacio de memoria, punteros a disco, recursos de red…).
  • Hilos de ejecución: También llamado proceso ligero, es un flujo de ejecución secuencial dentro de un proceso. En un proceso se pueden estar ejecutando uno o más hilos de ejecución a la vez. Los hilos permiten evitar «los cuellos de botella» en el rendimiento del sistema. Su origen puede venir determinado por varias razones: bloqueo de operaciones de E/S, bajo uso de CPU o debido al recurso contencioso, consistente en que dos o más tareas queden a la espera del uso exclusivo de un recurso.

 

El planificador es el componente de los sistemas multitarea y multiproceso encargado de repartir el tiempo de ejecución de un procesador entre los diferentes procesos que estén disponibles para su ejecución.
En los sistemas operativos de propósito general, existen tres tipos de planificadores:
  • Planificador a corto plazo: Planificador encargado de repartir el tiempo de proceso entre los procesos que se encuentran en memoria principal en un momento determinado.
  • Planificador a mediano plazo. Relacionado con aquellos procesos que no se encuentran en memoria principal. Se encarga de mover procesos entre memoria principal y la memoria de Swap (Disco).
  • Planificador a largo plazo:Planificador encargado del ciclo de vida de los procesos, desde que son creados en el sistema hasta su finalización.

 

Existen diferentes políticas de planificación con multitud de variaciones y especializaciones que permiten ser utilizadas para diferentes propósitos. En el apartado de referencias se encuentran enlaces a las explicaciones de algunas de ellas.
Paralelismo
Se definen como procesos paralelos aquellos que se ejecutan en el mismo instante de tiempo, debido a esto, este tipo de computación sólo es posible en sistema multiprocesador.
Concurrencia
Se definen como procesos concurrentes aquellos que se ejecutan en un mismo intervalo de tiempo pero no necesariamente de forma simultánea. A diferencia del paralelismo, este tipo de computación se puede realizar en sistema monoprocesador alternando la ejecución de las 2 tareas. En la siguiente imagen se puede observar esta diferencia.
Existe un método en java que permite obtener el número de procesadores disponibles en un sistema:
1
int countProcessors = Runtime.getRuntime().availableProcessors();

Ciclo de vida de un hilo de ejecución

El ciclo de vida de un hilo de ejecución representa los estados por los que este pasa desde que es creado hasta que completa su tarea o finaliza su por otra razón, cómo por ejemplo porque se produce un error que lo interrumpe.
Se pueden enumerar los siguientes estados:
  • Nuevo (new): En el momento en que se crea un nuevo Thread, este se sitúa en estado nuevo hasta que el programa inicia su ejecución. En este estado el hilo no se encuentra activo.
  • Ejecutable (runnable): En el momento en que se inicia el hilo mediante el método start() se considera que este se encuentra activo. En este momento el control de su ejecución pasa a ser del planificador que decidirá si se ejecuta inmediatamente o se mantiene a la espera en un pool hasta que decida ponerlo en ejecución.
  • En ejecución (running): En el momento en que el planificador escoge un hilo del pool para ser ejecutado, este pasa a estar en ejecución. Una vez en este estado, el hilo puede volver al estado de espera (ejecutable) si el planificador decide que su tiempo asignado de CPU ha finalizado aunque no haya completado su tarea. En este supuesto, deberá esperar a que el planificador vuelva a escogerlo para devolverlo a ejecución. Otras causas por las que un hilo puede abandonar este estado son los bloqueos o esperas o por su finalización.
  • Bloqueado/esperando (bloqued/waiting): Un hilo activo puede entrar en un estado de espera finito, por ejemplo durante operaciones de entrada/salida en las que debe esperar para obtener datos de un recurso. Cuando esta espera finaliza, el hilo vuelve al estado de ejecución. Este estado también se puede producir en caso de que el hilo de ejecución deba esperar a la realización de una tarea por parte de otro hilo. En este caso volverá al estado activo cuando el otro hilo envíe le una señal al hilo en espera para que siga su ejecución.
  • Finalizado (dead): Un hilo activo entra en este estado cuando completa su tarea o finaliza por otra causa, como por ejemplo que se produzca un error o se le envíe una señal de finalización.

Problemas de concurrencia

Cuando 2 o más hilos se ejecutan al mismo tiempo y tienen que competir por los mismos recursos o colaborar para producir un resultado, es posible que se produzcan situaciones no deseadas que alteren este resultado o incluso produzcan problemas de rendimiento considerables en el sistema.
Entre los problemas más corrientes y conocidos se encuentran los siguientes:
  • Condición de carrera (Race condition): Este problema se produce cuando 2 o más hilos de ejecución modifican un recurso compartido en un orden diferente al esperado, provocando un estado erróneo de este recurso. Por ejemplo, 2 hilos de ejecución leen es valor de una variable compartida, realizan un cálculo sobre este y actualizan de nuevo la variable con el resultado. Si no se sincroniza adecuadamente el acceso a dicha variable es posible que los hilos hayan realizado los cálculos en base a un valor obsoleto porque el otro hilo lo haya actualizado antes. En este caso, la solución pasa por disponer de mecanismos para sincronizar el acceso a los recursos compartidos de manera que la lectura y posterior actualización sean atómicas y no puedan producirse de forma concurrente.
  • Bloqueo mutuo (Deadlock): Este problema se produce cuando 2 o más hilos de ejecución compiten por un recurso o se comunican entre ellos y no pueden acceder al recurso quedando indefinidamente a la espera de que sea liberado pero esto no se produce nunca. Un ejemplo clásico sería el de 2 hilos A y B que tienen asignados 2 recursos R1 y R2 respectivamente. Si A require R2 y B requiere R1 pero estos no son liberados por sus poseedores en ese momento, tanto A como B se encuentran bloqueados a la espera de poder acceder a los recursos. En este caso, la solución pasa por impedir situaciones en que un hilo de ejecución quede bloqueado esperando un recurso compartido sin liberar antes los que tiene él tiene ocupados.

Referencias

Políticas de planificación de tareas

Guía Rápida Maven

Descripciones de los términos más conocidos

  • ArtifactId: Identificador de un proyecto en Maven. Dentro del repositorio es la carpeta última contenedora de los ficheros de la librería
  • groupId: Grupo identificador asociado al proyecto. Un proyecto debe pertenecer obligatoriamente a un grupo
  • archetpe:create Comando para crear un proyecto Maven vacío
mvn archetype:generate 
    -DgroupId=com.mycompany.app 
    -DartifactId=my-app 
    -DarchetypeArtifactId=maven-archetype-quickstart 
    -DinteractiveMode=false
  • package: Permite generar un jar, war o web desplegada (opción exploded). Está formado por la versión del proyecto y por el indicador de la construcción.

Ejemplo:    1.0         –    SNAPSHOT
(versión)      (indicador de proceso de construcción)

NOTA: Sise utiliza la agrupación de los 2 se considera que es la VERSIÓN la que se debe indicar en la mayoria de referencias de Poms dependientes o jerarquizados.

 

Para obtener la versión de Maven instalada en el sistema en Windows se debe ejecutar el siguiente comando:

mvn -version

Aparecerá por pantalla la versión de Maven instalada en el sistema.

Dentro de Maven se crea un directorio siguiendo el esquema definido por el standard project structure de Maven. Se compone de los siguientes elementos:

my-app
|
|-- pom.xml
|
|-- src
     |-- main
     |   |-- java
     |       |-- com
     |           |-- mycompany
     |               |-- app
     |                   |-- App.java
     |-- test
         |-- java
             |-- com
                 |-- mycompany
                     |-- app
                         |-- AppTest.java

Dónde src/main/java contiene el código fuente del proyecto, src/test/java contiene el código fuente de test y el fichero pom.xml es el Project Object Model oPOM.

El POM es una representación XML de un proyecto Maven contenido en un archivo denominado pom.xml.  Este fichero puede contener información de la configuración del proyecto, de las personas involucradas y del rol rol que ejercen, del sistema de control de incidencias, la organización, licencias, URL dónde reside el proyecto, dependencias del proyecto y todas las piezas que dan sentido al código. En el mundo de Maven, un proyecto no necesita contener ningún tipo de código, simplemente un pom.xml.

Imágenes con atributos alt

En desarrollos donde se emplee el tag <img> para que aparezca correctamente el mensaje al pasar por encima el ratón, será necesario añadir también el atributo title.

En el siguiente enlace se puede comprobar cómo funciona correctamente:

 

En la documentación oficial del W3Schools no aparece el atributo title

Todo parece indicar que es una especificación del IE10. No he sido capaz de encontrar un enlace donde oficialmente reste documentada esta implementación específica.

Sin embargo se confirma que si se utilizan los dos atributos (alt y title) conjuntamente se muestra correctamente el tip allí donde se haya aplicado y al pasar el ratón por encima aparece el mensaje de texto correctamente.

Closing a Window in Internet Explorer (All Versions)

I found this unique solution that allows us to close a windows (the window not opened through Javascript) using the Javascript window.close() method in IE where IE throws a prompt like «The Webpage you are viewing is trying to close the window. Do you want to close this window?»

Due to the security enhancements in IE, we can not close a window unless it is opened by an script.

The way to solve this problem consists in letting the browser thinks that the page is opened using an script so we can close the window easily.

Below you can see the implementation of the code:

<script type=»text/javascript»>

          functioncloseWP() {
                   var Browser = navigator.appName;
                   var indexB = Browser.indexOf(‘Explorer’);
 
                   if (indexB > 0) {
                          var indexV = navigator.userAgent.indexOf(‘MSIE’) + 5;
                          var Version = navigator.userAgent.substring(indexV, indexV + 1);
                          if (Version >= 7) {
                                  window.open(», ‘_self’, »);
                                  window.close();
                         } else if (Version == 6) {
                                             window.opener = null;
                                             window.close();
                                  } else {
                                            window.opener = »;
                                            window.close();
                                 }
 
                   } else {
                     window.close();
                   }
           }

</script>

The original source of this code can be found in this link.