Moin,
wir behandeln in Informatik gerade das Thema Nebenläufigkeit und Prozesssynchronisation.
An sich kein Problem: Es gibt einen kritischen Abschnitt, der synchronisiert werden muss, damit der Zugriff auf die Ressourcen nicht gleichzeitig abläuft. Dazu gibt es in Java ja das
Jetzt haben wir das Erzeuger-Verbraucher-Problem behandelt und ich blicke da irgendwie nicht ganz durch, auch was die entsprechenden Methoden in Java angeht.
Entsprechend folgendes Szenario:
Was ich jetzt nicht verstehe: Wir haben dann die Methoden
So sieht das ungefähr aus:
Speicher
Erzeuger
Verbrauch
Ja, ich weiß, der Code ist ranzig, aber darum soll es jetzt nicht gehen. Die Kiste ist nur eine Datenstruktur (Klasse), die eine Nummer enthält, also recht simpel.
Jetzt die Fragen:
Im Speicher sind die Methoden
Das müsste doch als Synchronisation reichen, oder? Wozu dann noch mit einer
Warum genau existiert dann das Erzeuger-Verbraucher-Problem?
Außerdem seht Ihr z. B. im
Ich hab's dann mal ausprobiert, das wegzulassen und es kam wirklich zu einer
Ich danke euch für Antworten.
Grüße
wir behandeln in Informatik gerade das Thema Nebenläufigkeit und Prozesssynchronisation.
An sich kein Problem: Es gibt einen kritischen Abschnitt, der synchronisiert werden muss, damit der Zugriff auf die Ressourcen nicht gleichzeitig abläuft. Dazu gibt es in Java ja das
synchronized
-Schlüsselwort, um diese Abschnitte zu definieren. Damit konnten wir das dann regeln, dass der Zugriff über Monitore abläuft und es zu keinen Komplikationen kommt.Jetzt haben wir das Erzeuger-Verbraucher-Problem behandelt und ich blicke da irgendwie nicht ganz durch, auch was die entsprechenden Methoden in Java angeht.
Entsprechend folgendes Szenario:
- Wir haben einen Speicher, der eine Kiste beinhaltet
- Der Erzeuger produziert Kisten und legt diese auf dem Speicher ab
- Der Verbraucher holt diese ab und kann dann was mit diesen anstellen
Was ich jetzt nicht verstehe: Wir haben dann die Methoden
object.wait()
und object.notify()
verwendet, damit die zwei Threads (Erzeuger u. Verbraucher) jeweils warten, bis der Platz frei (bzw. voll) ist und dann erst ihre Aktion ausführen.So sieht das ungefähr aus:
Java-Quellcode
- public class SPEICHER{
- private KISTE kiste;
- private Boolean frei;
- public SPEICHER(){
- frei = true;
- kiste = null;
- }
- public synchronized void Ablegen(KISTE k)
- {
- while(!frei){
- try{
- wait();
- }
- catch(Exception e){
- }
- }
- frei = false;
- kiste = k;
- System.out.println("Kiste Nr. " +kiste.NummerGeben()+ " abgelegt");
- notify();
- }
- public synchronized KISTE Holen()
- {
- KISTE k;
- while(frei){
- try{
- wait();
- }
- catch(Exception e){
- }
- }
- frei = true;
- k=kiste;
- kiste = null;
- System.out.println("Kiste Nr. " +k.NummerGeben()+" abgeholt");
- notify();
- return k;
- }
- }
Java-Quellcode
- public class ERZEUGER extends Thread {
- private SPEICHER speicher;
- private int zeit;
- private int kNummer;
- public ERZEUGER(SPEICHER s, int zeitNeu) {
- zeit = zeitNeu;
- speicher = s;
- kNummer = 0;
- }
- public void run() {
- while (true) {
- speicher.Ablegen(Produzieren());
- }
- }
- KISTE Produzieren() {
- long akt, ende;
- akt = System.currentTimeMillis();
- ende = akt + zeit;
- while (akt < ende) {
- try {
- wait(ende - akt);
- } catch (Exception e) {}
- akt = System.currentTimeMillis();
- }
- kNummer++;
- System.out.println("Kiste Nummer " + kNummer + " wurde produziert.");
- return (new KISTE(kNummer));
- }
- }
Java-Quellcode
- public class VERBRAUCHER extends Thread {
- private SPEICHER speicher;
- private int zeit;
- private Random zufall
- public VERBRAUCHER(SPEICHER s, int zeitNeu) {
- zeit = zeitNeu;
- speicher = s;
- zufall = new Random();
- }
- public void run() {
- while (true) {
- Einlagern(speicher.Holen());
- }
- }
- void Einlagern(KISTE kiste) {
- long akt, ende;
- akt = System.currentTimeMillis();
- ende = akt + zeit;
- while (akt < ende) {
- try {
- wait(ende - akt);
- } catch (Exception e) {}
- akt = System.currentTimeMillis();
- }
- System.out.println("Kiste Nummer " + kiste.NummerGeben() + " wurde eingelagert.");
- }
- }
Ja, ich weiß, der Code ist ranzig, aber darum soll es jetzt nicht gehen. Die Kiste ist nur eine Datenstruktur (Klasse), die eine Nummer enthält, also recht simpel.
Jetzt die Fragen:
Im Speicher sind die Methoden
Ablegen
und Holen
als Monitor erklärt, sodass der Zugriff auf diese jeweils nur von einem Objekt aus stattfinden sollte. Warum also haben wir dann die wait()
und notify()
-Methoden an der Stelle im Erzeuger
und Vebraucher
benötigt? Nach meinem Verständnis müsste doch zuerst der Erzeuger
den Monitor für sich sperren, sodass der Verbraucher
erstmal nichts abholen
kann, weil es nicht darf. Was genau macht der dann? Setzt er sich in eine Warteschlange für den Monitor, bis er intern dann den Zugriff bekommt? Sobald die Kiste dann abgelegt ist, wird der Monitor ja freigegeben und dann dürfte der Verbraucher
die Kiste abholen. Zugleich könnte der Erzeuger dann nichts ablegen.Das müsste doch als Synchronisation reichen, oder? Wozu dann noch mit einer
while
-Schleife pollen und solange warten, bis er das frei
mit dem entsprechenden Wert hat? Kann es sein, dass ich falsch verstehe, was synchronized
macht? Imo müsste das ja bereits reichen, damit es nicht zu diesem Szenario (Erzeuger und Verbraucher wollen gleichzeitig zugreifen) und folglich zu einer NullPointerException
kommt, oder? Selbst wenn diese unterschiedlich schnell arbeiten, wartet halt der andere durch das synchronized
entsprechend länger, bis er den Monitor bekommt.Warum genau existiert dann das Erzeuger-Verbraucher-Problem?
Außerdem seht Ihr z. B. im
Verbraucher
bei Zeile 24 das wait
. Ich dachte, das kann man eig. nur in Verbindung mit synchronized
verwenden? Was macht denn das da? Ist das sowas wie Thread.Sleep()
in .NET? Warum genau existiert denn in Java jetzt wait
, notify
und notifyAll
. Ich sehe da den Sinn irgendwie nicht.Ich hab's dann mal ausprobiert, das wegzulassen und es kam wirklich zu einer
NullPointerException
. synchronized
alleine reicht dann anscheinend nicht. Aber warum?Ich danke euch für Antworten.
Grüße
#define for for(int z=0;z<2;++z)for // Have fun!
Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose!
Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da
Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose!
Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da
Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Trade“ ()