Threads Consumer/Producer mit Zufallszahlen

devo22

Mitglied
Hi! Ein Beispiel zu Threads raubt mir noch den letzten Nerv :(

Ich soll zwei Threads erstellen, wobei ersterer Zufallszahlen produziert und zweiterer diese ausgeben soll. Zwischen den Threads soll es einen Buffer fixer Größer geben (ist der Buffer leer, muss der Consumer warten, ist der Buffer voll, muss der Producer warten). Das ganze soll doppelt implementiert werden -

1.) System-programmer's view mit wait(), notifyAll(), synchronized{} (Array für Buffer)
2.) Application-programmer's view: verwenden geeigneter Klassen aus der Java Library, um den Buffer zu implementieren

Ich bin leider Gottes eine ziemliche Niete in Java und das Beispiel bereitet mir im Prinzip von Anfang an Probleme ... das Produzieren von Zufallszahlen im Producer ist kein Problem, aber ich scheitere eigentlich schon beim Übergeben der Zahlen an den Buffer und in weiterer Folge an den Consumer.

Kann mir jemand helfen? Würde mich über jeden Tipp und jede Hilfestellung freuen!!! Danke schon mal im Voraus!!
 

devo22

Mitglied
Bei BlockingQueue (Java 2 Platform SE 5.0) ist Code dabei, den man fast 1:1 kopieren kann (und damit ein dezenter Hinweis auf Aufgabenteil 2 ;)). Ansonsten wären konkretere Frage nicht schlecht...
danke schon mal für den Hinweis :) hab versucht, das mal mit BlockingQueue zu machen ... ist das so in etwa richtig? Der Compiler schreit "missing return statement" an Zeile 26 ???:L

Java:
import java.util.*;
import java.util.concurrent.BlockingQueue;

class Producer2 implements Runnable {
  
   private final BlockingQueue queue;
   
   Producer2 (BlockingQueue q) { queue = q; }

   public void run() {
     try {
       while(true) { queue.put(produce()); }
     }
	 
	 catch (InterruptedException ex) { System.out.println("Something went wrong!"); }
   }
   Object produce() { 
   
			int size=100;
			int i;
			double numbers[] = new double[size];
				
			for (i=0; i<size; i++) {
				numbers[i] = Math.random()*99 + 1;
				}
          } 
 }

Wie bringe ich denn dann die Zahlen in die Consumer-Klasse, um sie auszugeben? Steh da gerade total auf dem Schlauch :(

Java:
import java.util.*;
import java.util.concurrent.BlockingQueue;

class Consumer2 implements Runnable {
   
   private final BlockingQueue queue;
   
   Consumer2 (BlockingQueue q) { queue = q; }
   
   public void run() {
   
   try {
       while(true) { consume(queue.take()); }
     }
	 
   catch (InterruptedException ex) { System.out.println("Something went wrong!"); }

	 }
   void consume(Object x) { ... }
 }

Danke für jede Hilfestellung ... war mal ganz gut in Java, hab aber ewig nichts mehr gemacht und jetzt steht es wirklich schlecht um meine Java-Kenntnisse ...
 

Marco13

Top Contributor
Morgen vielleicht. Aber: Produce sollte nur EIN Objekt zurückgeben - nämlich EINE Zufallszahl. Mit Generics wie BlockingQueue<Float> kann man das auch typsicher machen.
 

devo22

Mitglied
So, ich hab die erste Implementierung so weit fertig - denke ich. Ist das so richtig oder habe ich was übersehen?

Java:
import java.util.*;
import java.io.*;

public class ProducerConsumer {

  public static void main (String [] args) {
	FixedSizedBuffer f1 = new FixedSizedBuffer();
    Thread p1 = new Producer(20, f1);
    Thread c1 = new Consumer(20, f1);
    p1.start();
    c1.start();
    
    try {
    	p1.join();
    	c1.join();
    }
	catch (InterruptedException e) {
	return;
  }
}
}

public class Producer extends Thread {
  	private int j;
	private int newnumber;
  	private FixedSizedBuffer producerbuffer;
  	
  	public Producer (int size, FixedSizedBuffer buffer) {
  		j = size;
  		producerbuffer = buffer;
    }
    
    public void run() {
    	for (int i = 0; i < j; i++) {
    	    try {
				newnumber = (int) (Math.random()*99);
    	    	producerbuffer.givenumber(newnumber);
    	    } catch (InterruptedException e) {return;}
    		
    	}
    }
  }

public class Consumer extends Thread {
  	private int j;
  	private FixedSizedBuffer consumerbuffer;
  	
  	public Consumer (int size, FixedSizedBuffer buffer) {
  		j = size;
  		consumerbuffer = buffer;
    }
    
    public void run() {
    	int consumervalue;
    	for (int i = 0; i < j; i++) {
    		try {
    			consumervalue = consumerbuffer.printnumber();
    		}  catch (InterruptedException e) {return;}
    	}
    }
  }

class FixedSizedBuffer {
  		private int contents;
  		private boolean empty = true;
  		
  		public synchronized void givenumber (int i) throws InterruptedException { 
  			while (empty == false) {
  				try { wait(); }
  				catch (InterruptedException e) {throw e;}
  			}
  			contents = i;
  			empty = false;
  			notifyAll();
  		} 
  		
  		public synchronized int printnumber () throws InterruptedException {
  			while (empty == true)  {
  				try { 	wait(); }
  				catch (InterruptedException e) {throw e;}
  			}
  			empty = true;
  			notifyAll();
  			int newvalue = contents;
  			System.out.println(newvalue);
  			return newvalue;
  		}
}

Sieht zumindest richtig aus und funktioniert, nur beim Buffer bin ich mir nicht ganz sicher, ob das so stimmt.

Was die zweite Implementierung mit BlockingQueue angeht, bin ich aber keinen Schritt weiter. Würde mich freuen, wenn mir da jemand helfen könnte!
 

devo22

Mitglied
So, hab jetzt doch auch das mit BlockingQueue hingekriegt ... hoffe ich :D alles, was ich zu diesem Zeitpunkt noch bräuchte, wäre eine Bestätigung, dass ich das alles richtig gemacht habe ;)

Java:
import java.util.*;
import java.util.concurrent.BlockingQueue;

public class ProducerBQ extends Thread {
  	private int j;
	private int newnumber;
  	private final BlockingQueue producerbuffer;
  	
  	public ProducerBQ (int size, BlockingQueue buffer) {
  		j = size;
  		producerbuffer = buffer;
    }
    
    public void run() {
    	for (int i = 0; i < j; i++) {
    	    try {
				newnumber = (int) (Math.random()*99);
    	    	producerbuffer.put(newnumber);
    	    } catch (InterruptedException e) {return;}
     	}
    }
 }

import java.util.*;
import java.util.concurrent.BlockingQueue;

public class ConsumerBQ extends Thread {
  	private int j;
  	private BlockingQueue consumerbuffer;
  	
  	public ConsumerBQ (int size, BlockingQueue buffer) {
  		j = size;
  		consumerbuffer = buffer;
    }
    
    public void run() {
    	Object consumervalue;
    	for (int i = 0; i < j; i++) {
    		try {
    			consumervalue = (int) consumerbuffer.take();
				System.out.println(consumervalue);
    		}  catch (InterruptedException e) {return;}
    	}
    }
  }

import java.util.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.io.*;

public class ProducerConsumerBQ {

  public static void main (String [] args) {
	BlockingQueue f1 = new LinkedBlockingQueue();
    Thread p1 = new ProducerBQ(20, f1);
    Thread c1 = new ConsumerBQ(20, f1);
    p1.start();
    c1.start();
    
    try {
    	p1.join();
    	c1.join();
    }
	catch (InterruptedException e) {
	return;
  }
}
}
 

Marco13

Top Contributor
Beim ersten Überfliegen sieht es richtig aus.

Die "Kür": Deine beiden Programme sind ja von der Gesamtstruktur her sehr ähnlich (und das ist auch gut und richtig so) denn sie machen ja beide das gleiche. Der wichtigste Unterschied ist, dass in einem Fall die LinkedBlockingQueue verwendet wird, und im anderen Fall der FixedSizeBuffer. Wenn man erreichen könnte dass
class FixedSizeBuffer implements BlockingQueue
gilt, könnte man alle Klassen gleich lassen und wirklich mit einer Zeile
Java:
//BlockingQueue q = new LinkedBlockingQueue(); // Entweder so
BlockingQueue q = new FixedSizeBuffer(); // oder so
zwischen beiden Varianten hin- und herschalten. Ist aber vielleicht ein bißchen aufwändiger und hier gar nicht nötig. (Fiel mir nur auf, weil bei dem FixedSizeBuffer die Methoden "printnumber" und "givenumber" hießen - ein erster Schritt wäre eben, die beiden Methoden als "take" und "put" zu implementieren...)
 

Oben