Autor Tema: Thread run Java synchronized programa con dos hilos productor y consumidor chars  (Leído 14007 veces)

manuelfer

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 17
    • Ver Perfil
Hola, como andan a todos. Tengo una duda de este problemas, que el productor tiene que generar caracteres aleatorios (la cantidad que quiera) y el consumidor lo tiene que comer.
El problema es que cuando los dos hilos (consumidor y productor) empiezan al mismo tiempo, hay aveces que primero sale el Consumidor, y segundo el Productor (Cosa que nunca puede pasar porque primero tiene que el productor producir un carácter y después si o si el consumidor.

Ejemplo correcto:
Productor 1: R
Consumidor 1: R
Productor 2: J
Consumidor 2: J
........
....

Ejemplo lo que me pasa aveces a mi:
Consumidor 1: R
Productor 1: R
Consumidor 2: K
Productor 2: K
......
...

Acá va el código para que puedan ver como lo estoy haciendo hasta el momento.


Productor.java
Código: [Seleccionar]
import java.util.Random;

public class Productor extends Thread {
private Pila pila;
private String alfabeto = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private char c;
private Random random = new Random();


public Productor (Pila pila, int cant, int ms){
this.pila = pila;

}

public Productor (Pila p){
this.pila = p;;
}

public void run (){
for (int i = 1; i < 11 ; i++){
c = alfabeto.charAt(random.nextInt(26));
pila.poner(c);
System.out.println("Productor "+i+": "+c);
}

}
}

Consumidor.java
Código: [Seleccionar]
public class Consumidor extends Thread {
private Pila pila;


   
public Consumidor (Pila pila){
this.pila = pila;
}

public void run (){


for(int i = 1; i < 11; i++){
char c;
c = pila.sacar();
System.out.println("Consumidor "+i+": "+c);
}

}

}

Pila.java
Código: [Seleccionar]
import java.util.ArrayList;


public class Pila {
ArrayList <Character> pila = new ArrayList<Character>();
private char c;

public synchronized  char sacar(){

if(pila.size()==0){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

c = pila.remove(0);
notify();

return c;
}

public synchronized char poner(char c){
if (pila.size()!=0){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

pila.add(c);
notify();

return c;

}

}

Main.java

Código: [Seleccionar]
public class Main {
public static void main(String[] args) {
Pila pila = new Pila();

Productor pr = new Productor(pila);
Consumidor cs = new Consumidor (pila);
pr.start();
cs.start();


}
}

Conclusion: No me sale, que primero SIEMPRE, salga el productor y después el consumidor. Muchas gracias
« Última modificación: 28 de Enero 2016, 09:11 por Ogramar »

Lorenzo31

  • Avanzado
  • ****
  • APR2.COM
  • Mensajes: 381
    • Ver Perfil
Re:Duda - Productor y Consumidor [Java]
« Respuesta #1 en: 25 de Enero 2016, 11:39 »
Buenas, sin ser un experto en Java, creo que debes usar el método notify() una vez despierte del wait uno de los Threads, para que avise al otro, mientras no notify() no continuará el otro Thread.

(Perdona ahora veo que has usado el notify() ya. Luego le hecho un vistazo a fondo y miro si puedo ayudarte, esta claro que el problema esta en la sincronización de los threads, eso seguro).

Un saludo.
« Última modificación: 25 de Enero 2016, 11:42 por Lorenzo31 »

manuelfer

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 17
    • Ver Perfil
Re:Duda - Productor y Consumidor [Java]
« Respuesta #2 en: 25 de Enero 2016, 15:25 »
Sisi, lo he usado a notify () y wait (), pero sin embargo no me funciono. He estado días intentando y no.. si me puedes solucionar el problema te lo agradecería !!

Lorenzo31

  • Avanzado
  • ****
  • APR2.COM
  • Mensajes: 381
    • Ver Perfil
Re:Duda - Productor y Consumidor [Java]
« Respuesta #3 en: 25 de Enero 2016, 15:53 »
Buenas tardes, ya lo he solucionado para que vaya como tu quieres,

Primero comentarte que no es ningun problema con los Threads, porque si te fijas las numeraciones de Productor y Consumidor son perfectamente correctas, no se come una letra distinta a la que les toque.

Por tanto es un simple problema de cordinacion con los System.out.println.

Lo que he hecho yo es unir los bucles en uno en el main y ya va perfectamente.
Y la pila, la he puesto como Stack no ArrayList que es como corresponderia.

PILA
Código: [Seleccionar]
import java.util.Stack;


public class Pila {
Stack <Character> pila = new Stack<Character>();
private char c;

public synchronized  char sacar(){

if(pila.size()==0){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

c = pila.remove(0);
notify();

return c;
}

public synchronized char poner(char c){
if (pila.size()!=0){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

pila.add(c);
    notify();

return c;

}

}


CONSUMIDOR

Código: [Seleccionar]
public class Consumidor extends Thread {
private Pila pila;

    public Consumidor (Pila pila){
this.pila = pila;
}

public void run (int i){
        char c;
c = pila.sacar();

   System.out.println("Consumidor "+i+": "+c);
   }
}

PRODUCTOR

Código: [Seleccionar]
import java.util.Random;

public class Productor extends Thread {
private Pila pila;
private String alfabeto = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private char c;
private Random random = new Random();


public Productor (Pila pila, int cant, int ms){
this.pila = pila;

}

public Productor (Pila p){
this.pila = p;;
}

public void run (int i){

c = alfabeto.charAt(random.nextInt(26));
System.out.println("Productor "+i+": "+c);
pila.poner(c);

}
}


MAIN

Código: [Seleccionar]
public class Main {

    public static void main(String[] args)  throws InterruptedException{
Pila pila = new Pila();

Productor pr = new Productor(pila);
Consumidor cs = new Consumidor (pila);

for (int i = 1; i < 11 ; i++){
pr.run(i);

cs.run(i);

        }

}
}

manuelfer

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 17
    • Ver Perfil
Re:Duda - Productor y Consumidor [Java]
« Respuesta #4 en: 25 de Enero 2016, 15:58 »
Muchísimas gracias !!!! , perdon por mi ignorancia pero que diferencias hay entre Stack y ArrayList?

Lorenzo31

  • Avanzado
  • ****
  • APR2.COM
  • Mensajes: 381
    • Ver Perfil
Re:Duda - Productor y Consumidor [Java]
« Respuesta #5 en: 25 de Enero 2016, 16:26 »
Bueno un Stack es un LIFO last in first out. que es lo que tu necesitas ahí.

Modifica los metodos de agregar o quitar del STACK que no lo hice, fui muy rápido.

https://docs.oracle.com/javase/7/docs/api/java/util/Stack.html

Mirate los Method Sumary y sustituye add() por push() remove .... etc 
Sino dejalo como ArrayList tambien va a funcionarte. Es una tonteria con matices minimos, espero te haya servido de ayuda y mas o menos haga lo que tu querias.

Tienes si quieres en esta web un curso de java que no es que sea cojonudo, es lo siguiente de cojonudo.


Te dejo Link:
http://aprenderaprogramar.com/index.php?option=com_content&view=category&id=68&Itemid=188
« Última modificación: 25 de Enero 2016, 16:31 por Lorenzo31 »

manuelfer

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 17
    • Ver Perfil
Re:Duda - Productor y Consumidor [Java]
« Respuesta #6 en: 25 de Enero 2016, 16:30 »
Muchísimas gracias nuevamente, copie tal cual y no me imprime, estoy viendo que es lo que me falta y no me estoy dando cuenta..

manuelfer

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 17
    • Ver Perfil
Re:Duda - Productor y Consumidor [Java]
« Respuesta #7 en: 25 de Enero 2016, 16:41 »
Ya esta, ya me funciono perfecto!! Gracias!!

Lorenzo31

  • Avanzado
  • ****
  • APR2.COM
  • Mensajes: 381
    • Ver Perfil
Re:Duda - Productor y Consumidor [Java]
« Respuesta #8 en: 25 de Enero 2016, 18:25 »
Bueno, despues de pasarme una hora mirando, voy a pasarte la forma correcta de hacer esto.

La clave es que al hacer un Thread.run() realmente no estas usando el Objeto Thread solo invocando al metodo run() del mismo.

Así, para actuar sobre el objeto, debes invocar al Thread.start()

Bien, lo que ocurre es que el println, no tiene una sincrinización tal como tu la pretendias, lo he podido solucionar con un sleep y el bucle conjunto.

Te dejo la solución final que yo he encontrado, y si te parece ya podemos pedir a los Administradores que cierren el hilo.

PILA
Código: [Seleccionar]
import java.util.Stack;


public class Pila {
Stack <Character> pila = new Stack<Character>();
private char c;

public synchronized char sacar(){

if(pila.empty()){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

c = pila.pop();
notify();

return c;
}

public synchronized char poner(char c){
if (!pila.empty()){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

pila.push(c);
    notify();

return c;

}

}

PRODUCTOR

Código: [Seleccionar]
import java.util.Random;

public class Productor extends Thread {
private Pila pila;
private String alfabeto = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private char c;
    private int i;
private Random random = new Random();


public Productor (Pila pila, int cant, int ms){
this.pila = pila;
}

public Productor (Pila p, int i){
this.pila = p;
this.i = i;
}

public synchronized  void run (){
   
c = alfabeto.charAt(random.nextInt(26));
pila.poner(c);
               System.out.println("Productor "+i+": "+c);
       




           }
     
}


CONSUMIDOR

Código: [Seleccionar]

public class Consumidor extends Thread {
private Pila pila;
private int i;

    public Consumidor (Pila pila, int i){
this.pila = pila;
this.i= i;
}

public synchronized void run (){
       
        char c;

        c = pila.sacar();

               System.out.println("Consumidor "+i+": "+c);
         
    }
   
  }


MAIN

Código: [Seleccionar]
public class Main {

    public static void main(String[] args) {
Pila pila = new Pila();




for(int i=1; i<11; i++){
Productor pr = new Productor(pila, i);
Consumidor cs = new Consumidor (pila, i);

        pr.start();

cs.start();


try{ Thread.sleep(10);
  }catch(InterruptedException e){}
          }

       

}
}


manuelfer

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 17
    • Ver Perfil
Re:Duda - Productor y Consumidor [Java]
« Respuesta #9 en: 25 de Enero 2016, 18:35 »
Perfecto lorenzo, hay un problema que me olvide de decirte. El ejercicio pide que por parámetro le pidas a productor crear X cantidad de caracteres y a consumidor tb. Ej:
Consumidor cs = new Consumidor (pila, 5);
Productor p = new Productor (pila, 5);

Yo lo había pensado en pasarle el 5 por parámetro al for, pero el for esta en el main..

Lorenzo31

  • Avanzado
  • ****
  • APR2.COM
  • Mensajes: 381
    • Ver Perfil
Re:Duda - Productor y Consumidor [Java]
« Respuesta #10 en: 25 de Enero 2016, 18:47 »
Bueno, entonces, por narices has de hacer el bucle for en los Threads.

Trata de ajustar con sleep() para que de tiempo a cada uno a hacer un System.out.println en Consumidor y Productor.

Ya nos contarás que tal.

manuelfer

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 17
    • Ver Perfil
Re:Duda - Productor y Consumidor [Java]
« Respuesta #11 en: 25 de Enero 2016, 18:50 »
Claro, yo lo he hecho con sleep, Productor 300ms y consumidor 600ms, para que primero largue el productor siempre. Pero desp el ejercicio dice que tienen que largar los 2 en 400 ms por defecto.

Lorenzo31

  • Avanzado
  • ****
  • APR2.COM
  • Mensajes: 381
    • Ver Perfil
Re:Duda - Productor y Consumidor [Java]
« Respuesta #12 en: 25 de Enero 2016, 19:19 »
pues ajusta los sleeps para que lo haga en 400, deberia poder hacerse.

manuelfer

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 17
    • Ver Perfil
Re:Duda - Productor y Consumidor [Java]
« Respuesta #13 en: 25 de Enero 2016, 19:23 »
Claro, pero como tengo que pasar por parámetros la cantidad de productor y consumidor que quiero, saque el for del main los puse en cada hilo, y me pasa lo mismo, que cuando salen al mismo tiempo (ósea en 400ms), vuelvo a lo mismo de antes, todo sin sincronizar me sale

Lorenzo31

  • Avanzado
  • ****
  • APR2.COM
  • Mensajes: 381
    • Ver Perfil
Re:Duda - Productor y Consumidor [Java]
« Respuesta #14 en: 25 de Enero 2016, 19:33 »
Y el ejercicio pide expresamente que salga por pantalla sincronizado?

manuelfer

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 17
    • Ver Perfil
Re:Duda - Productor y Consumidor [Java]
« Respuesta #15 en: 25 de Enero 2016, 19:35 »
No lo especifica, pero se supone que si, porque nunca puede salir primero el consumidor y despues el productor. No tendría coherencia

Lorenzo31

  • Avanzado
  • ****
  • APR2.COM
  • Mensajes: 381
    • Ver Perfil
Re:Duda - Productor y Consumidor [Java]
« Respuesta #16 en: 25 de Enero 2016, 22:16 »
Técnicamente, sale antes el Productor, de lo contrario sería EMPTY el Stack(Pila) y el Consumidor no podria coger nada.

Otra cosa son los prints del sistema, copiame el codigo final, cuando lo tengas y miro de ver si sé encontrar como hacerlo

Lorenzo31

  • Avanzado
  • ****
  • APR2.COM
  • Mensajes: 381
    • Ver Perfil
Re:Duda - Productor y Consumidor [Java]
« Respuesta #17 en: 26 de Enero 2016, 14:47 »
Bueno, te dejo aquí el ejercicio ajustado, para que salga productor consumidor, No se porque (bueno si lo se, system.out.println trabaja como objeto PrintStream y limpia buffer con salto de linea, no se porque al inicio retiene dos Productores y dos Consumidores)

El resto ya sale bien, no se puede ajustar mas con Sleep ya.

Te lo dejo aquí, si logras ajustar las primeras lineas del System.out.println dimelo para yo también saber como hacerlo.

PILA
Código: [Seleccionar]
import java.util.Stack;


public class Pila {
Stack <Character> pila = new Stack<Character>();
private char c;

public synchronized char sacar(){

if(pila.empty()){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

c = pila.pop();
notify();

return c;
}

public synchronized char poner(char c){
if (!pila.empty()){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

pila.push(c);
    notify();

return c;

}

}

PRODUCTOR
Código: [Seleccionar]
import java.util.Random;

public class Productor extends Thread {
private Pila pila;
private String alfabeto = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private char c;
    private int i;
private Random random = new Random();


public Productor (Pila pila, int cant, int ms){
this.pila = pila;
}

public Productor (Pila p, int i){
this.pila = p;
this.i = i;
}

public synchronized  void run (){
   
        for(int x=1; x<i; x++){
c = alfabeto.charAt(random.nextInt(26));
pila.poner(c);
               System.out.println("Productor "+x+": "+c);
               
             try{ Thread.sleep(7); }catch(InterruptedException e){}   
            }




           }
     
}



CONSUMIDOR

Código: [Seleccionar]
public class Consumidor extends Thread {
private Pila pila;
private int i;
    private char c;

    public Consumidor (Pila pila, int i){
this.pila = pila;
this.i= i;
}

public synchronized void run (){
       
        try{ Thread.sleep(1); }catch(InterruptedException e){}
System.out.flush();
        for(int x=1; x<11; x++){
        c = pila.sacar();

               System.out.println("Consumidor "+x+": "+c);
               
              try{ Thread.sleep(7); }catch(InterruptedException e){}
            }
    }
   
  }

MAIN
Código: [Seleccionar]
public class Main {

    public static void main(String[] args) {
Pila pila = new Pila();

Productor pr = new Productor(pila, 11);
Consumidor cs = new Consumidor (pila, 11);

        pr.start();

cs.start();



          }
}

manuelfer

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 17
    • Ver Perfil
Re:Duda - Productor y Consumidor [Java]
« Respuesta #18 en: 26 de Enero 2016, 22:46 »
Me anda ahora, proba vos a ver si te funciona tmb.

Productor
Código: [Seleccionar]
import java.util.Random;

public class Productor extends Thread {
private Pila pila;
private String alfabeto = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private char c;
private Random random = new Random();
private int cant, ms;


public Productor (Pila pila, int cant, int ms){
this.pila = pila;
this.cant = cant;
this.ms = ms;

}

public Productor (Pila p){
this.pila = p;
}

public void run (){
for (int i = 1; i < cant+1; i++){
c = alfabeto.charAt(random.nextInt(26));
System.out.println("Productor "+i+": "+c);
pila.poner(c);

try {
Thread.sleep(ms);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

}
}

Consumidor
Código: [Seleccionar]
public class Consumidor extends Thread {
private Pila pila;
private int cant,ms;
   
public Consumidor (Pila pila, int cant, int ms){
this.pila = pila;
this.cant = cant;
this.ms = ms;

}

public void run (){
char c;
for (int i = 1 ; i < cant + 1; i++){
c = pila.sacar();
System.out.println("Consumidor "+i+": "+c);

try {
Thread.sleep(ms);
} catch (InterruptedException e) {
e.printStackTrace();
}
}



}

}

Pila
Código: [Seleccionar]
import java.util.ArrayList;



public class Pila {
ArrayList <Character> pila = new ArrayList <Character>();
private char c;

public synchronized  char sacar(){

if(pila.size()==0){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

c = pila.remove(0);
notify();

return c;
}

public synchronized void poner(char c){

if (pila.size()!=0){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
pila.add(c);
notify();

}

}

Main
Código: [Seleccionar]
public class Main {
public static void main(String[] args){
Pila pila = new Pila();

Productor pr = new Productor(pila,10, 500);
Consumidor cs = new Consumidor (pila,10,500);

pr.start();
cs.start();

}
}

Lorenzo31

  • Avanzado
  • ****
  • APR2.COM
  • Mensajes: 381
    • Ver Perfil
Re:Duda - Productor y Consumidor [Java]
« Respuesta #19 en: 27 de Enero 2016, 09:23 »
Si señor ya funciona, no necesita el milisegundo que yo le hacia dormir al consumidor antes de entrar en el bucle (pretendia retrasarlo esa milesima, que es poquisimo, pero no es necesario porque solo el start() del Thread Productor ya hace que se retrase esa milesima y unas pocas más, el Consumidor)

Voy a comentarte algo que debes tener en cuenta, se supone que el ejercicio final, solicitaras via Consola la introduccion de la cantidad de caracteres a generar, y los milisegundos totalles del delay de cada generación de letra (y consumo de la misma)

Ten en cuenta poner en los sleep de Productor y Consumidor, la mitad de ese delay general.

try {
            Thread.sleep(ms/2);
         } catch (InterruptedException e) {

 

Sobre la educación, sólo puedo decir que es el tema más importante en el que nosotros, como pueblo, debemos involucrarnos.

Abraham Lincoln (1808-1865) Presidente estadounidense.

aprenderaprogramar.com: Desde 2006 comprometidos con la didáctica y divulgación de la programación

Preguntas y respuestas

¿Cómo establecer o cambiar la imagen asociada (avatar) de usuario?
  1. Inicia sesión con tu nombre de usuario y contraseña.
  2. Pulsa en perfil --> perfil del foro
  3. Elige la imagen personalizada que quieras usar. Puedes escogerla de una galería de imágenes o subirla desde tu ordenador.
  4. En la parte final de la página pulsa el botón "cambiar perfil".