[código] Problema Productor-Consumidor: sincronización de Hilos en Java (2)
Continuando en el tema de los hilos … En el siguiente ejemplo veremos el uso e implementación de la sincronización de hilos en Java. De nuevo vamos a tratar el ejemplo del Productor-Consumidor (antes lo hicimos sin sincronización), esta vez con los subprocesos sincronizados (es recomendable que te hayas leido la anterior entrada).
La clase Bufer es la misma de la del ejemplo anterior:
// La interfaz Bufer especifica los métodos llamados por el Productor y el Consumidor.
public interface Bufer {
public void establecer( int valor ); // colocar valor en Bufer
public int obtener(); // devolver valor de Bufer
}
Como segunda medida crearemos la clase BuferSincronizado.java, que implementa la clase Bufer.java, y en la cual se declaran los métodos estableces(int) y obtener() con el prefijo synchronized.
Lo que se hace en estos casos es poner algo así como un semáforo. Para ello usamos una variable llamada cuentaBuferOcupado, que tomará dos posibles valores: 1 si el buffer está ocupado, y 0 si el buffer está vacio.
Fijemonos entonces en el método establecer, en donde hay un ciclo que se repite siempre y cuando el bufer esté lleno (while(cuentaBuferOcupado ==1)). Si esta cnodición se cumple, se muestra un mensaje y se invoca al método wait(), para poner al subproceso en espera.
De lo contrario, es decir, cuando el bufer está vacio, se escribe un dato en el bufer y se actualiza la variable cuentaBuferOcupado (indicando que el bufer está ahora ocupado). Posteriormente se usa el método notify(), el cual avisa a los subprocesos que están en espera que pase al estado “listo”.
De igual forma, el método obtener(), usa la variable cuentaBuferOcupado para determinar cuando puede o no tomar un valor del bufer.
// BuferSincronizado sincroniza el acceso a un solo entero compartido.
public class BuferSincronizado implements Bufer
{
private int bufer = -1; // compartido por los subprocesos productor y consumidor
private int cuentaBuferOcupado = 0; // cuenta de búferes ocupados
// colocar valor en búfer
public synchronized void establecer( int valor )
{
// obtener nombre del subproceso que llamó a este método, para mostrarlo en pantalla
String nombre = Thread.currentThread().getName();
// mientras no haya ubicaciones vacías, colocar subproceso en estado de espera
while ( cuentaBuferOcupado == 1 ) {
// mostrar información del subproceso y del búfer, después esperar
try {
System.err.println( nombre + " trata de escribir." );
mostrarEstado( "Bufer lleno. " + nombre + " espera." );
wait();
}
// si se interrumpió el subproceso en espera, imprimir el rastreo de la pila
catch ( InterruptedException excepcion ) {
excepcion.printStackTrace();
}
} // fin de instrucción while
bufer = valor; // establecer nuevo valor de bufer
// indicar que el productor no puede almacenar otro valor
// sino hasta que el consumidor recupere el valor actual del búfer
++cuentaBuferOcupado;
mostrarEstado( nombre + " escribe " + bufer );
notify(); // indicar al subproceso en espera que entre al estado listo
} // fin del método establecer; se libera el bloqueo en BuferSincronizado
// devolver valor de bufer
public synchronized int obtener()
{
// obtener nombre del subproceso que llamó a este método, para mostrarlo en pantalla
String nombre = Thread.currentThread().getName();
// mientras no haya datos que leer, colocar subproceso en estado de espera
while ( cuentaBuferOcupado == 0 ) {
// mostrar información del subproceso y del búfer, después esperar
try {
System.err.println( nombre + " trata de leer." );
mostrarEstado( "Bufer vacio. " + nombre + " espera." );
wait();
}
// si se interrumpió el subproceso en espera, imprimir el rastreo de la pila
catch ( InterruptedException excepcion ) {
excepcion.printStackTrace();
}
} // fin de instrucción while
// indicar que el productor puede almacenar otro valor
// ya que el consumidor acaba de recuperar el valor de bufer
--cuentaBuferOcupado;
mostrarEstado( nombre + " lee " + bufer );
notify(); // indicar al subproceso en espera que esté listo para ejecutarse
return bufer;
} // fin del método obtener; libera bloqueo en BuferSincronizado
// mostrar la operación actual y el estado del búfer
public void mostrarEstado( String operacion )
{
StringBuffer lineaSalida = new StringBuffer( operacion );
lineaSalida.setLength( 40 );
lineaSalida.append( bufer + "\t\t" + cuentaBuferOcupado );
System.err.println( lineaSalida );
System.err.println();
}
} // fin de la clase BuferSincronizado
La salida de este programa es la siguiente:
# java PruebaBuferCompartido2
Operacion Bufer Cuenta ocupado
Estado inicial -1 0
Productor escribe 1 1 1
Consumidor lee 1 1 0
Productor escribe 2 2 1
Productor trata de escribir.
Bufer lleno. Productor espera. 2 1
Consumidor lee 2 2 0
Productor escribe 3 3 1
Consumidor lee 3 3 0
Consumidor trata de leer.
Bufer vacio. Consumidor espera. 3 0
Productor escribe 4 4 1
Productor termino de producir.
Terminando Productor.
Consumidor lee 4 4 0
Consumidor leyo valores, dando un total de: 10.
Terminando Consumidor.
Como puedes ver, en este caso si el productor intenta escribir un dato en el bufer, pero este está ocupado, espera a que el consumidor lea el dato y desocupe el bufer; y viceversa.
14 Comentarios | deja el tuyo





bien un codigo q m servira debido a los hilos y la sincronizacion , gracias por la aportacion
saludos ( :
ESTA CHIDO TU CODIGO Y GRACIAS POR APORTARLO AL FORO TE LO AGRADESCO ME SIRVIO PARA MI TRABAJO DEL ESCUELA
Donde quedo el main ?
aqui…
http://casidiablo.net/java-hilos-productor-conumidor-no-sincronismo/
…tienes que leer el capitulo anterior
Excelente, tu blog es muy bueno y tiene cosas muy interesantes…
Hola, felicidades por esta página, me encantan los códigos que exponen aquí y me han ayudado muchísimo a entender ciertas cosas, justo ahora estoy en un proyecto donde tengo que implementar el problema de productor/consumidor en java con semáforos, y este código me vino de lujo, pero tengo una duda (talves algo tonta pero aun no lo puedo comprender), para que sirve el metodo “Mostrar estado”??? mas explicitamente que hace cuando se crea el stringbuffer??? busque para que es un string buffer en varias páginas pero no logro comprender que hace o para que sirve, en que difiere en usar un string normal???… espero me ayuden…
Saludos…
hola ta bueno xD asi es que voy a persentar mi trabajo ahora xD gg
Hola solo decirte FELICIDADES POR TU PAGINA!!
Nos estas ayudando muchisimo a los que estamos estudiando java, o en mi caso reciclandonos despues de 9 años sin ejercer de Informático, a pelearme con este nuevo lenguaje para mi.
Te apunto y te recomendare como pagina de referencia de consulta en mi academia.
GRACIAS POR TU GRAN TRABAJO.
hola MUCHISIMAS gracias..!!! lo recomendare a mis amix y bueno… sos brillante…..
Wow, demasiado bueno…!! Muchas gracias, me has ayudado un monton… Bendiciones