Threads de Control

El lenguaje Java y el sistema de ejecuci�n soportan la sincronizaxi�n de threads mediante el uso de monitores. En general, un monitor est� asociado con un objeto especifico (una condici�n variable) y funciona como un bloqueo para ese dato. Cuando un thread mantiene el monitor para alg�n dato del objeto, los otros threads est�n bloqueados y no pueden ni inspeccionar ni modificar el dato.

Los segmentos de c�digo dentro de programa que acceden al mismo dato dentro de threads concurrentes separados son conocidos como secciones cr�ticas. En el lenguaje Java, se pueden marcar las secciones cr�ticas del programa con la palabra clave synchronized.

Nota: Generalmente, la secci�n cr�ticas en los programas Java son m�todos. Se pueden marcar segmentos peque�os de c�digo como sincronizados.

Sin embargo, esto viola los paradigmas de la programaci�n orientada a objetos y produce un c�digo que es d�ficil de leer y de mantener. Para la mayor�a de los prop�sitos de programaci�n en Java, es mejor utilizar synchronized s�lo a nivel de m�todos.

En el lenguaje Java se asocia un �nico monitor con cada objeto que tiene un m�todo sincronizado. La clase CubbyHole del ejemplo Producer/Consumer de la p�gina anterior tiene dos m�todos sincronizados: el m�todo put(), que se utiliza para cambiar el valor de CubbyHole, y el m�todo get(), que se utiliza para el recuperar el valor actual. As� el sistema asocia un �nico monitor con cada ejemplar de CubbyHole.

Aqu� tienes el c�digo fuente del objeto CubbyHole. Las l�neas en negrita proporcionan la sincronizaci�n de los threads.

class CubbyHole {
    private int contents;
    private boolean available = false;

    public synchronized int get() {
        while (available == false) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
        available = false;
        notify();
        return contents;
    }

    public synchronized void put(int value) {
        while (available == true) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
        contents = value;
        available = true;
        notify();
    }
}

La clase CubbyHole tiene dos variables privadas: contents, que es el contenido actual de CubbyHole, y la variable booleana available, que indica si se puede recuperar el contenido de CubbyHole. Cuando available es verdadera indica que el Productor ha puesto un nuevo valor en CubbyHole y que el Consumidor todav�a no la ha consumido. El Consumidor s�lo puede consumir el valor de CubbyHole cuando available es verdadera.

Como CubbyHole tiene dos m�todos sincronizados, java proporciona un �nico monitor para cada ejemplar de CubbyHole (incluyendo el compartido por el Productor y el Consumidor). Siempre que el control entra en un m�todo sincronizado, el thread que ha llamado el m�todo adquiere el monitor del objeto cuyo m�todo ha sido llamado. Otros threads no pueden llamar a un m�todo sincronizado del mismo objeto hasta que el monitor sea liberado.

Nota:

Los Monitores Java son Re-entrantes.

Es decir, el mismo thread puede llamar a un m�todo sincronizado de un objeto para el que ya tiene el monitor, es decir, puede re-adquirir el monitor.

As�, siempre que el Productor llama al m�todo put() de CubbyHole, adquiere el monitor del objeto CubbyHole, y as� evita que el consumidor pueda llamar al m�todo get() de CubbyHole. (El m�todo wait() libera temporalmente el monitor como se ver� m�s adelante).

public synchronized void put(int value) {
        // El productor adquiere el monitor
    while (available == true) {
        try {
            wait();
        } catch (InterruptedException e) {
        }
    }
    contents = value;
    available = true;
    notify();
        // El productor libera el monitor
}

Cuando el m�todo put() retorna, el Productor libera el monitor y por lo tanto desbloquea el objeto CubbyHole.

Siempre que el Consumidor llama al m�todo get() de CubbyHole, adquiere el monitor de ese objeto y por lo tanto evita que el productor pueda llamar al m�todo put().

public synchronized int get() {
        // El consumidor adquier el monitor
    while (available == false) {
        try {
            wait();
        } catch (InterruptedException e) {
        }
    }
    available = false;
    notify();
    return contents;
        // el Consumidor libera el monitor
}

La adquisici�n y liberaci�n del monitor la hace autom�ticamente el sistema de ejecuci�n de Java. Esto asegura que no puedan ocurrir condiciones de competici�n en la implementaci�n de los threads, asegurando la integridad de los datos.

Prueba esto: Elimina las l�neas que est�n en negrita en el listado de la clase CubbyHole mostrada arriba. Recompila el programa y ejecutalo de nuevo. �Qu� sucede? Como no se ha realizado ning�n esfuerzo expl�cito para sicronizar los threads, el Consumidor consume con un abandono temerario y obtiene s�lo una ristra de ceros, en lugar de obtener los enteros entre 0 y 9 exactamente una vez cada uno.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP
ARTÍCULO ANTERIOR

SIGUIENTE ARTÍCULO