Suscribirse al Feed
03Ene

[código] Programación concurrente: uso de semáforos

Hablamamos en anteriores entradas acerca de la programación multihilo o concurrente en Java, e hicimos algunos ejemplos de sincronización. De nuevo veremos algo de subprocesamiento múltiple, esta vez explicando el uso de los semáforos. Primero veamos algo de teoría:

Un semáforo binario es un indicador (S) de condición que registra si un recurso está disponible o no. Un semáforo binario sólo puede tomar dos valores: 0 y 1. Si, para un semáforo binario, S = 1 entonces el recurso está disponible y la tarea lo puede utilizar; si S = 0 el recurso no está disponible y el proceso debe esperar.
Los semáforos se implementan con una cola de tareas o de condición a la cual se añaden los procesos que están en espera del recurso. Sólo se permiten tres operaciones sobre un semáforo:

  • Inicializar
  • Espera (wait)
  • Señal (signal)

En algunos textos, se utilizan las notaciones P y V para las operaciones de espera y señal respectivamente, ya que ésta fue la notación empleada originalmente por Dijkstra (el creador de la solución) para referirse a las operaciones.

Lo importante aquí es entender de verdad cómo funcionan los semáforos en Java. Por eso, basta de práctica y vamos al código. Aún así, sería bueno que le echaras un ojo a los siguientes documentos de referencia:

Problemas al NO usar semáforos

Lo primero es ver una aplicación fictica corriendo SIN el uso de los semáforos, para luego entender mejor su utilidad. Su pongamos que tenemos 4 procesos (p1, p2, p3, p4), cada proceso realiza su "tarea" simultaneamente (durante un tiempo indefinido) y posteriormente termina. Supongamos además que necesitamos que se ejecuten primero los procesos P1 y P3, y luego P2 y P4.

Tenemos entonces P1.java:


public class p1 extends Thread {
	public void run() {
		try {
			sleep((int) Math.round(500 * Math.random() - 0.5));
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("P1");
	}
}

P2.java


public class p2 extends Thread {
	public void run() {
		try {
			sleep((int) Math.round(500 * Math.random() - 0.5));
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("P2");
	}
}

P3.java

public class p3 extends Thread {
	public void run() {
		try {
			sleep((int) Math.round(500 * Math.random() - 0.5));
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("P3");
	}
}

y P4.java

public class p4 extends Thread {
	public void run() {
		try {
			sleep((int) Math.round(500 * Math.random() - 0.5));
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("P4");
	}
}

y la clase SinSemaforos.java, que lanza los subprocesos:

public class SinSemaforos {
	public static void main(String[] args) {
		(new Thread(new p1())).start();
		(new Thread(new p2())).start();
		(new Thread(new p3())).start();
		(new Thread(new p4())).start();
	}
}

Ejecutando varias veces este programa, tendremos salidas como:

# java SinSemaforos
P4
P2
P1
P3
# java SinSemaforos
P2
P1
P3
P4
# java SinSemaforos
P2
P1
P4
P3

Como puedes ver, los procesos se ejecutan sin cumplir la condición más importante: que se ejecuten primero los procesos P1 y P3, y posteriormente P2 y P4. Solucionemos esto con el uso de semáforos!

Solución usando semáforos

En este caso vamos a usar la clase Semaphore, del paquete java.util.concurrent. A darle entonces:

Tenemos entonces P1.java:

import java.util.concurrent.Semaphore;
public class p1 extends Thread  {
	protected Semaphore oFinP1;
	public p1(Semaphore oFinP1) {
		this.oFinP1 = oFinP1;
	}
	public void run()  {
		try {
			sleep((int) Math.round(500 * Math.random() - 0.5));
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("P1");
		this.oFinP1.release(2);
	}
}

P2.java

import java.util.concurrent.Semaphore;
public class p2 extends Thread  {
	protected Semaphore oFinP1;
	protected Semaphore oFinP3;
	public p2(Semaphore oFinP1,Semaphore oFinP3) {
		this.oFinP3 = oFinP3;
		this.oFinP1 = oFinP1;
	}
	public void run()  {
		try {
		this.oFinP1.acquire();
		this.oFinP3.acquire();
		} catch(Exception e) {
			e.printStackTrace();
		}
		try {
			sleep((int) Math.round(500 * Math.random() - 0.5));
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("P2");
	}
}

P3.java

import java.util.concurrent.Semaphore;
public class p3 extends Thread  {
	protected Semaphore oFinP3;
	public p3(Semaphore oFinP3) {
		this.oFinP3 = oFinP3;
	}
	public void run()  {
		try {
			sleep((int) Math.round(500 * Math.random() - 0.5));
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("P3");
		this.oFinP3.release(2);
	}
}

y P4.java

import java.util.concurrent.Semaphore;
public class p4 extends Thread  {
	protected Semaphore oFinP1;
	protected Semaphore oFinP3;
	public p4(Semaphore oFinP1,Semaphore oFinP3) {
		this.oFinP3 = oFinP3;
		this.oFinP1 = oFinP1;
	}
	public void run()  {
		try {
			this.oFinP1.acquire();
			this.oFinP3.acquire();
			} catch(Exception e) {
				e.printStackTrace();
			}
		try {
			sleep((int) Math.round(500 * Math.random() - 0.5));
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("P4");
	}
}

y la clase UsoSemaforos.java, que lanza los subprocesos:

import java.util.concurrent.Semaphore;
public class UsoSemaforos {
	protected static Semaphore oFinP1,oFinP3;
	public static void main(String[] args) {
		 oFinP1 = new Semaphore(0,true);
		 oFinP3 = new Semaphore(0,true);
		 (new Thread(new p1(oFinP1))).start();
		 (new Thread(new p2(oFinP1,oFinP3))).start();
		 (new Thread(new p3(oFinP3))).start();
		 (new Thread(new p4(oFinP1,oFinP3))).start();
	}
}

Ejecutando varias veces el programa, podemos ver como los subprocesos P1 y P3 se ejecutan siempre de primeras, y los procesos P2 y P4, de ultimas:

#java UsoSemaforos
P3
P1
P2
P4
#java UsoSemaforos
P1
P3
P2
P4
#java UsoSemaforos
P3
P1
P4
P2
#java UsoSemaforos
P1
P3
P4
P2

Conclusiones...

  • Lo primero es el método acquire() de la clase Semaphore. Este método bloquea el semáforo premanetemente (wait); mientras que,
  • el método release() de la clase Semaphore, libera el semáforo para los demás procesos (signal).

Descargar ejemplos:

13 Comentarios para “[código] Programación concurrente: uso de semáforos”

« 1 2 Todos

  1. a gravatar

    noxusrules dice:  


    Excelente articulo, yo estoy apenas entrandole a esto de la programacion y la neta hasta ahora que ya puedo programar un poco mas y por lo menos le entiendo a los codigos que leo en internet (que por cierto espero ser yo el que ponga codigos hehe) le estoy encontrando el gusto, tamben gracias por el articulo porque tengo que entregar un reporte sobre esto para la semana que viene, y esta pagina va a mis favoritos desde ya!!! Un saludo

  2. a gravatar

    Cristian dice:  


    Me alegra que te haya servido… no te olvides añadir este blog a tu lector de feeds!

    Un saludo!

  3. a gravatar

    Denisse dice:  


    como hago para hacerlo ejecutable en linux Red Hat 9.0 y ademas como se utiliza la clase Semaphore, del paquete java.util.concurrent ????

  4. a gravatar

    Cristian dice:  


    @Denisse: descargas los programas, los compilas así:

    javac *java

    Y lo ejecutas así:

    java UsoSemaforos

    Un saludo!

  5. a gravatar

    Denisse dice:  


    Gracias por responderme.
    ya compile el programa pero me salen errores en import java.util.concurrent por que no lo encuentra como hago para añadir esta libreria????
    de antemano gracias

  6. a gravatar

    Denisse dice:  


    Ah otra preguntita mas si no es molestia puedo adaptar el programas para 6 procesos que se ejecuten en orden?????

  7. a gravatar

    Cristian dice:  


    Por un lado… tal vez sea la versión de JDK. Con respecto a lo otro, por supuesto, puedes modificar el programa como deseas.

    Un saludo!

  8. a gravatar

« 1 2 Todos

 

 

Antes de comentar... recuerda que no hago tareas

Te invito a subscribirte al feed RSS. ¿No sabes que es un lector de Feeds?

© 2007 - 2008 Dezinerfolio. Todos los derechos reservados.
Powered by Wordpress. Entradas RSS