Foros aprenderaprogramar.com
Aprender a programar => C, C++, C#, Java, Visual Basic, HTML, PHP, CSS, Javascript, Ajax, Joomla, MySql y más => Mensaje iniciado por: manuelfer en 22 de Enero 2016, 04:01
-
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
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
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
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
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
-
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.
-
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 !!
-
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
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
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
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
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);
}
}
}
-
Muchísimas gracias !!!! , perdon por mi ignorancia pero que diferencias hay entre Stack y ArrayList?
-
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
-
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..
-
Ya esta, ya me funciono perfecto!! Gracias!!
-
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
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
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
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
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){}
}
}
}
-
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..
-
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.
-
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.
-
pues ajusta los sleeps para que lo haga en 400, deberia poder hacerse.
-
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
-
Y el ejercicio pide expresamente que salga por pantalla sincronizado?
-
No lo especifica, pero se supone que si, porque nunca puede salir primero el consumidor y despues el productor. No tendría coherencia
-
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
-
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
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
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
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
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();
}
}
-
Me anda ahora, proba vos a ver si te funciona tmb.
Productor
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
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
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
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();
}
}
-
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) {
-
Muchas gracias, pq siempre dividido 2??
-
Si no te entendí mal, cuando le pasas los milisegundos, es el tiempo que deben tardar tanto PRODUCTOR como CONSUMIDOR en generar y comer la letra, es decir entre los dos juntos.
Entonces eso significa que el PRODUCTOR debe tardar la mitad de los milisegundos pasados por el usuario, y el CONSUMIDOR la otra mitad.
Entendí así cuando me lo dijiste, y que como máximo tardaran 400 ms entre los dos, osea 200 y 200.
A eso me referia con ms/2.