Threads de Control

Las lecciones anteriores contenan ejemplos con threads asncronos e independientes. Esto es, cada thread contena todos los datos y mtodos necesarios y no requerian recursos externos. Adems, los threads de esos ejemplos se ejecutaban en su propio espacio sin concernir sobre el estado o actividad de otros threads que se ejecutaban de forma concurrente.

Sin embargo, existen muchas situaciones interesantes donde ejecutar threads concurrentes que compartan datos y deban considerar el estado y actividad de otros threads. Este conjunto de situaciones de programacin son conocidos como escenarios 'productor/consumidor'; donde el productor genera un canal de datos que es consumido por el consumidor.

Por ejemplo, puedes imaginar una aplicacin Java donde un thread (el productor) escribe datos en un fichero mientras que un segundo thread (el consumidor) lee los datos del mismo fichero. O si tecleas caracteres en el teclado, el thread productor situa las pulsaciones en una pila de eventos y el thread consumidor lee los eventos de la misma pila. Estos dos ejemplos utilizan threads concurrentes que comparten un recurso comn; el primero comparte un fichero y el segundo una pila de eventos.

Como los threads comparten un recurso comn, deben sincronizarse de alguna forma.

Esta leccin ensea la sincronizacin de threads Java mediante un sencillo ejemplo de productor/consumidor.

.El Ejemplo Productor/Consumidor

El Productor genera un entero entre 0 y 9 (inclusive), lo almacena en un objeto "CubbyHole", e imprime el nmero generado. Para hacer ms interesante el problema de la sincronizacin, el prodcutor duerme durante un tiempo aleatorio entre 0 y 100 milisegundos antes de repetir el ciclo de generacin de nmeros.

class Producer extends Thread {
    private CubbyHole cubbyhole;
    private int number;

    public Producer(CubbyHole c, int number) {
        cubbyhole = c;
        this.number = number;
    }

    public void run() {
        for (int i = 0; i < 10; i++) {
            cubbyhole.put(i);
            System.out.println("Productor #" + this.number + " pone: " + i);
            try {
                sleep((int)(Math.random() * 100));
            } catch (InterruptedException e) {
            }
        }
    }
}

El Consumidor, estndo hambriento, consume todos los enteros de CubbyHole (exactamenten el mismo objeto en que el productor puso los enteros en primer lugar) tan rpidamente como estn disponibles.

class Consumer extends Thread {
    private CubbyHole cubbyhole;
    private int number;

    public Consumer(CubbyHole c, int number) {
        cubbyhole = c;
        this.number = number;
    }

    public void run() {
        int value = 0;
        for (int i = 0; i < 10; i++) {
            value = cubbyhole.get();
            System.out.println("Consumidor #" + this.number + " obtiene: " + value);
        }
    }
}

En este ejemplo el Productor y el Consumidor comparten datos a travs de un objeto CubbyHole comn. Observara que ninguno de los dos hace ningn esfuerzo sea el que sea para asegurarse de que el consumidor obtiene cada valor producido una y slo una vez. La sincronizacin entre estos dos threads realmente ocurre a un nivel inferior, dentro de los mtodos get() y put() del objeto CubbyHole. Sin embargo, asumamos por un momento que estos dos threads no estn sincronizados y veamos los problemas potenciales que podra provocar esta situacin.

Un problema sera cuando el Productor fuera ms rpido que el Consumidor y generara dos nmeros antes de que el Consumidor tuviera una posibilidad de consumir el primer nmero. As el Consumidor se saltara un nmero. Parte de la salida se podra parecer a esto.

    . . .
Consumidor #1 obtiene: 3
Productor #1 pone: 4
Productor #1 pone: 5
Consumidor #1 obtiene: 5
    . . .

Otro problema podra aparecer si el consumidor fuera ms rpido que el Productor y consumiera el mismo valor dos o ms veces. En esta situacin el Consumidor imprimir el mismo valor dos veces y podra producir una salida como esta.

    . . .
Productor #1 pone: 4
Consumidor #1 obtiene: 4
Consumidor #1 obtiene: 4
Productor #1 pone: 5
    . . .

De cualquier forma, el resultado es errneo. Se quiere que el consumidor obtenga cada entero producido por el Productor y slo una vez. Los problemas como los escritos anteriormente,se llaman condiciones de carrera. Se alcanzan cuando varios threads ejecutados asncronamente intentan acceder a un mismo objeto al mismo tiempo y obtienen resultados errneos.

Para prevenir estas condiciones en nuestro ejemplo Productor/Consumidor, el almacenamiento de un nuevo entero en CubbyHole por el Productor debe estar sincronizado con la recuperacin del entero por parte del Consumidor. El Consumidor debe consumir cada entero exactamente una vez. El programa Productor/Consumidor utiliza dos mecanismos diferentes para sincronizar los threads Producer y Consumer; los monitores, y los mtodos notify() y wait().

.Monitores

Los objetos, como el CubbyHole que son compartidos entre dos threads y cuyo acceso debe ser sincronizado son llamados condiciones variables. El lenguaje Java permite sincronizar threads alrededor de una condicin variable mediante el uso de monitores. Los monitores previenen que dos threads accedan simultneamente a la misma variable.

.Los mtodos notify() y wait()

En un nivel superior, el ejemplo Productor/Consumidor utiliza los mtodos notify() y wait() del objeto para coordinar la activadad de los dos threads. El objeto CubyHole utiliza notify() y wait() para asegurarse de que cada valor situado en l por el Productor es recuperado una vez y slo una por el Consumidor.

.El programa Principal

Aqu tienes una pequea aplicacin Java que crea un objeto CubbyHole, un Producer, un Consumer y arranca los dos threads.

class ProducerConsumerTest {
    public static void main(String[] args) {
        CubbyHole c = new CubbyHole();
        Producer p1 = new Producer(c, 1);
        Consumer c1 = new Consumer(c, 1);

        p1.start();
        c1.start();
    }
}

.La Salida

Aqu tienes la salida del programa ProducerConsumerTest.

Producer #1 pone: 0
Consumidor #1 obtiene: 0
Productor #1 pone: 1
Consumidor #1 obtiene: 1
Productor #1 pone: 2
Consumidor #1 obtiene: 2
Productor #1 pone: 3
Consumidor #1 obtiene: 3
Productor #1 pone: 4
Consumidor #1 obtiene: 4
Productor #1 pone: 5
Consumidor #1 obtiene: 5
Productor #1 pone: 6
Consumidor #1 obtiene: 6
Productor #1 pone: 7
Consumidor #1 obtiene: 7
Productor #1 pone: 8
Consumidor #1 obtiene: 8
Productor #1 pone: 9
Consumidor #1 obtiene: 9

COMPARTE ESTE ARTÍCULO

ENVIAR A UN AMIGO
COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN GOOGLE +
ARTÍCULO ANTERIOR

SIGUIENTE ARTÍCULO

HAY 1 COMENTARIOS
  • Anónimo dijo:

    Hola muy buena la explicaion sobre threads, pero tuvieras algun ejemplo pero aplicado a action sript 2 o php

Conéctate o Regístrate para dejar tu comentario.