Paquete añadido en Java 5, que contiene un conjunto de clases para hacer más fácil el desarrollo de aplicaciones concurrentes
Se trata de una biblioteca que contiene estructuras de datos y clases que proporcionen seguridad de hilos e interfaces que ayudan a normalizar los procesos multi-hilo.
Executor– Interface pensada para implementar clases para lanzamiento de tareas
La implementación más sencilla podría ser:
ExecutorService– Es una interface que nos permite lanzar nuestras clases Runnables. Podemos obtener una instancia, desde la clase Executors, a la vez que definimos características.
En el siguiente ejemplo, creamos un ExecutorService que solo tiene capacidad para lanzar 2 hilos.
Si intentamos enviar tres hilos, el tercero se quedara aparcado hasta que alguno de los anteriores finalice
Nota
La clase Mensaje la hemos definido en un ejercicio anterior, y solo le hemos añadido un constructor que recibe una string, para simplificar la codificación actual
ScheduledExecutorService – Es una interface semejante a Executor y ExecutorService pero realiza las tareas de forma periódica, o diferidas en el tiempo
Podemos obtener un ejecutor de una sola hebra con
Executors.newSingleThreadScheduledExecutor()
O uno multi hebra (por ejemplo 3) con
Executors.newScheduledThreadPool(3)
Para lanzar los procesos podemos hacerlo como indican las líneas 21-22 en donde lanzaríamos m1, después de esperar 5 segundos (TimeUnit.SECONDS) o esperando únicamente 1 segundo, como se hace en las líneas 25-26
En la linea23-24, utilizamos el método scheduleAtFixedRate Que nos permite indicar que queremos que el hilo sea lanzado repetidas veces, en este caso, lanzamos el trabajo m2, después de esperar 2 segundos, cada 10 segundos.
En la línea 29 damos la orden de cerrar todos los “executors” cuando terminen los trabajos, y como deseamos ver funcionando la reentrada de m2, lo que hacemos es definir un sleep en la línea 28, para que no inicie la orden hasta que hayan pasado 20 segundos,
Las clases Future y ScheduleFuture son variables que nos permite controlar en qué estado se encuentra el Thread. Luego, podríamos preguntar por su estado con
La salida con newSingleThreadScheduledExecutor()
Mientras que si utilizamos newScheduledThreadPool(3), seria
ThreadPoolExecutor-Implementación de Executor que nos permite controlar el número de hilos que se quieren lanzar, el total de hilos a lanzar como máximo, cuanto tiempo queremos que este activa antes de eliminarla, así como preparar soluciones para el caso de que se generen demasiados hilos, o controlar como se generan los hilos
TimeUnit – Clase estática que nos permite indicar las unidades de tiempo, y realizar conversiones entre ellas.
DAYS, HOURS, MICROSECONDS, MILLISECONDS, MINUTES, NANOSECONDS, SECONDS
Colecciones sincronizadas
ConcurrentMap– Interface equivalente a Map pero con los problemas de sincronización solucionados
CopyOnWriteArrayList– Se trata de un objeto ArrayList, con capacidad de trabajo multihilo
BlockingQueue– Es una colección Queu segura para tratamiento multihilo
SynchronousQueues– Es una colección Queu que para cada operación de inserción, necesita una operación de eliminación desde otro hilo
Datos sincronizados
Otro problema que podemos tener es que operaciones simples, como puede se el incremento (i++) no es segura, ya que internamente se compone de múltiples operaciones, para solucionarlos están la serie de campos Atomic. P. ejemplo
AtomicInteger con métodos como
- decrementAndGet() Decrementa en 1 el valor, y lo devuelve (–i).
- getAndAdd(int delta) Devuelve el valor y suma el valor indicado
- getAndDecrement() Devuelve el valor y decrementa (i–)
- getAndIncrement() Devuelve valor e incrementa (i++)
- getAndSet(int newValue) Devuelve el valor actual y coloca el nuevo
- incrementAndGet() Incrementa y devuelve (++i)
Se dispone de los siguientes tipos Atomic
Clases control
Semaphore – Permite controlar el número de hilos que pueden acceder a un recurso concreto en un momento determinado. Evita que haya un número excesivo de hilos en la cola del recurso, ya que el Semaphore los bloquea