Threads Counter mit ungeraden Zahlen

BodyLAB

Bekanntes Mitglied
Hallo,

habe zwei Fragen zu einem Code.
1. Warum werden nicht nur ungerade Zahlen ausgegeben?
2. Der Quellcode soll so Synchronisiert werden das nur ungerade Zahlen ausgegeben werden ohne eine weiter Variabele oder die main Methode zu ändern.

Java:
package Aufgabe2;

public class Counter extends Thread {
    static Integer counter = 0;

    public void run() {
        while (counter < 1000) {
                increment();
                System.out.println(counter);
                increment();
        }
    }

    private void increment() {
        counter++;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 5; i++)
            new Counter().start();
    }

}

Zu 1. Es werden deswegen nicht nur ungerade Zahlen ausgegeben weil die Threads um das Objekt counter konkurrieren. Sie greifen alle auf das Objekt zu und verändern es. Somit ist immer unklar welcher Wert in counter steckt. Dazu kommt das System.out.println gepuffert wird und man nicht genau sagen kann wann die Ausgabe erfolgt und wann eben das Objekt erneut geändert wurde.

Kann man das verstehen und wäre das ansatzweise Korrekt?

Zu 2.
Hier bin ich gescheitert und glaube das ich synchronized nicht verstehe :-(
Java:
package Aufgabe2;

public class Counter extends Thread {
    static Integer counter = 0;
    
    public Counter(String n) {
        super(n);
    }

    public void run() {
        while (counter < 1000) {
        synchronized (this) {
                System.out.print("Name: " + this.getName() + " ");
                increment();
                System.out.println(counter);
                increment();
            }
        }
    }

    private void increment() {
        counter++;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 5; i++)
            new Counter("" + i).start();
    }

}

Das war meine Idee. Leider ohne Erfolg. Bin davon ausgegangen das synchronized für das Objekt Counter mit der instanz 0 z. B. dann blockiert und erst diese instanz fertig laufen darf. Das scheint wohl nicht so zu sein oder? Das wäre jedoch sehr merkwürdig da man dann ja nie eine Klasse die Synchronisiert ist mit mehreren instanzen synchron laufen lassen dürft! Deswegen muss meine Annahme wohl falsch sein. Wo dann der Fehler steckt weiß ich nicht. Der aller erste Ansatz war die increment Methode mit synchronized auszustatten (ging auch nicht).

Danke vorab 🙂
 
Also, die Idee mit synchronized ist schon gut. Du gibst bei synchronized an, welches Objekt quasi der Lock ist. Und von dem Objekt kann immer nur ein Thread gleichzeitig den Lock haben.

Jetzt schauen wir uns mal, welche Objekte du erstellst und welche Locks die verwenden:

Du erstellst fünf Objekte vom Typ Counter - nennen wir die mal passend counter0 bis counter4.

Welches Objekt verwendet counter0 als Lock? Nun this - was counter0 entspricht.
Welches Objekt verwendet counter1 als Lock? Nun this - was counter1 entspricht.
Sprich jedes Objekt verwendet seinen eigenen Lock und synchronziert sich damit nur mit sich selber. Was wie du festgestellt hast, recht witzlos ist.

Du musst also ein Objekt beim synchronized verwenden, dass in allen Objekten verwendet wird. Die erste Idee wäre, counter zu verwenden - das ist ja static, aber das wird leider auch nicht funktionieren, da counter++ in wirklichkeit ein neues counter Objekt erzeugt. (Autoboxing / Unboxing lässt grüßen).

Das heißt, leg einfach ein neues Objekt in main an - z.B. per Object sharedLock = new Object(); und übergib das (und zwar allen das gleiche) deinen Counter-Klassen und verwende das im synchronized-Block.
 
Hallo,
ja so ist es zumindest synchronisiert. Was mich nur wundert ist die Aufgabe, denn dort steht ja folgendes:
Synchronisieren Sie den Quellcode, so dass nur ungerade Zahlen ausgegeben werden. Fügen Sie der Klasse keine weiteren Variablen hinzu und verändern Sie auch nicht die main() Methode.

Doch hier würde ich ja eine weiteres Datenelement hinzufügen und die main-Metehode ändern.
Fügen Sie der Klasse keine weiteren Vaiablen hinzu => sind doch Datenelemente gemeint oder 🙃
Verändern Sie auch nicht die main Methode => also sicher die gesamte Main Methode.

Doch wie soll es anders gehen. So dreht man sich doch nur im Kreis oder 😱
Java:
public class Counter extends Thread {
    static Integer counter = 0;
    private Object lock;
   
    public Counter(String n, Object lock) {
        super(n);
        this.lock = lock;
    }

    public void run() {
       
        while (counter < 1000) {
            synchronized (lock) {
                System.out.print("Name: " + this.getName() + " ");
                increment();
                System.out.println(counter);
                increment();
            }
        }
    }

    private void increment() {
        counter++;
    }

    public static void main(String[] args) {
        Object lock = new Object();
        for (int i = 0; i < 5; i++)
            new Counter("" + i, lock).start();
    }

}


______
Welches Objekt ist den nun der Monitor wenn die run Methode synchronized ist? Also so:
Java:
public synchronized void run() { ... }
Wer wäre in diesem Falle der Monitor? Counter oder Thread
 
Zuletzt bearbeitet:
Dann solltet du deinen counter
auch prüfen ob er gerade oder ungerade ist und nur bei gerade das print aufrufen.
Tipp modulo könnte helfen um auf gerade oder ungerade zu prüfen
 
Dann solltet du deinen counter
auch prüfen ober gerade oder ungerade ist und nur bei gerade das print aufrufen.
Tipp modulo könnte helfen um auf gerade oder ungerade zu prüfen
Das hatte ich schon. Dort ist das Problem dass dann erneut Daten verloren gehen. Da ja immer mal wieder die anderen Threads in die Quere kommen und man in der if() Abfrage unterbrochen werden kann etc.
Denn ich bekomme dann nur misst raus.

Java:
public class Counter extends Thread {
    static Integer counter = 0;
  
    public Counter(String n) {
        super(n);
    }

    public void run() {
      
        while (counter < 1000) {
          
                System.out.print("Name: " + this.getName() + " ");
                increment();
            if(counter % 2 == 1)
                System.out.println(counter);
                increment();
          
        }
    }

    private void increment() {
        counter++;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 5; i++)
            new Counter("" + i).start();
    }

}

Ausgabe:
Name: 1 Name: 4 Name: 4 Name: 3 Name: 4 Name: 3 Name: 3 Name: 2 Name: 0 Name: 2 Name: 0 Name: 3 Name: 4 1
Name: 4 27
Name: 3 Name: 0 29
Name: 3 33
Name: 3 35
Name: 3 37
Name: 3 39
Name: 3 41
Name: 3 43
Name: 3 45
Name: 3 47
Name: 3 49
Name: 3 51
Name: 3 53
Name: 3 55
Name: 3 Name: 2 57
Name: 3 61
Name: 3 63
Name: 3 65
Name: 3 67
Name: 3 69
Name: 3 71
Name: 3 73
Name: 3 75
Name: 3 77
Name: 3 79
Name: 3 81
Name: 3 83
Name: 3 85
Name: 3 87
Name: 3 89
Name: 3 91
Name: 3 93
Name: 3 95
Name: 3 97
Name: 3 99
Name: 3 101
Name: 3 103
Name: 3 105
Name: 3 107
Name: 3 109
Name: 3 111
Name: 3 113
Name: 3 115
Name: 3 117
Name: 3 119
Name: 3 121
Name: 3 123
Name: 3 125
Name: 3 127
Name: 3 129
Name: 3 131
Name: 3 133
Name: 3 135
Name: 3 137
Name: 3 139
Name: 3 141
Name: 0 143
Name: 4 Name: 1 Name: 3 Name: 0 145
Name: 2 Name: 4 Name: 0 Name: 3 Name: 1 Name: 3 Name: 0 Name: 0 Name: 0 Name: 0 Name: 0 Name: 4 Name: 4 Name: 4 153
Name: 4 181
Name: 0 Name: 4 Name: 4 Name: 3 Name: 1 Name: 4 Name: 4 Name: 4 Name: 4 Name: 4 Name: 4 Name: 4 183
Name: 2 Name: 0 Name: 4 Name: 4 Name: 4 Name: 4 Name: 4 Name: 4 Name: 4 Name: 4 Name: 4 Name: 4 Name: 4 Name: 3 Name: 1 Name: 3 Name: 3 Name: 3 Name: 4 Name: 4 Name: 0 207
Name: 0 249
Name: 0 251
Name: 0 253
Name: 0 Name: 4 Name: 3 Name: 1 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 4 Name: 4 Name: 4 255
Name: 2 Name: 0 Name: 0 Name: 0 Name: 0 Name: 0 Name: 0 Name: 4 Name: 4 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 1 Name: 1 Name: 1 Name: 1 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 3 Name: 0 Name: 4 Name: 4 Name: 4 Name: 4 301
Name: 2 Name: 4 Name: 4 Name: 4 Name: 4 Name: 4 Name: 4 Name: 4 Name: 4 Name: 0 Name: 0 Name: 0 Name: 0 Name: 0 Name: 0 Name: 0 Name: 0 Name: 0 Name: 0 Name: 0 Name: 0 Name: 0 Name: 0 Name: 0 Name: 0 Name: 0 Name: 0 Name: 0 Name: 0 Name: 0 Name: 0 Name: 0 Name: 0 Name: 0 Name: 0 Name: 0 Name: 0 Name: 3 Name: 1 Name: 4 929
Vielleicht ist das aber ja gewollt hehe
 
Die Main Methode muss ich nicht mehr ändern. Doch es wird ein Datenelement zur Klasse hinzugefügt. Glaube das geht gar nicht anders.
Java:
public class Counter extends Thread {
    static Integer counter = 0;
    private static final Object monitor = new Object();

    public Counter(String n) {
        super(n);
    }

    public void run() {

        while (counter < 1000) {
            synchronized(monitor) {
                System.out.print("Name: " + this.getName() + " ");
                increment();
                System.out.println(counter);
                increment();
            }
        }
    }

    private void increment() {
        counter++;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 5; i++)
            new Counter("" + i).start();
    }

}
 
Kann mir noch jemand erklären was das hier bedeutet? Also welches Objekt wird hier als Monitor verwendet?

Java:
class TestThread extends Thread {
    private int i = 0;
    
    public synchronized void run() {
        while(true) i++;
    }
}

Was bedeutet es wenn man die run Methode synchronized macht.
 
welches Objekt wird hier als Monitor verwendet?
Da das synchronized Schlüsselwort an einer Instanzmethode geschrieben wurde, ist der Monitor immer das Objekt, auf dem du die Methode aufrufst.
In deinem Fall wirst du aber vermutlich die run-Methode nicht direkt aufrufen, sondern der Thread, den du da startest, ruft die Methode auf.
Nichtsdestotrotz ist der Monitor die TestThread-Instanz, die du startest - intern ruft der dadurch neu erzeugte Thread ja die run() Methode auf der TestThread-Instanz auf.
Was bedeutet es wenn man die run Methode synchronized macht.
Dasselbe, was es bedeutet, wenn du jede andere Methode synchronized machst: Dass nur ein Thread zur Zeit die Methode aufrufen kann. Und in diesem Fall wird es halt der Thread sein, der durch die TestThread Instanz repräsentiert wird.
 
Die Main Methode muss ich nicht mehr ändern. Doch es wird ein Datenelement zur Klasse hinzugefügt. Glaube das geht gar nicht anders.
Naja, in der Aufgabe steht, dass man keine neue Variable hinzufügen soll. Da steht aber nicht, dass man die vorhandene nicht ändern darf.
Meine Idee wäre, eine Klasse zu bauen, die ein Integer verwaltet(erhöht und zurück gibt) und dann "counter" ein Objekt dieser Klasse werden zu lassen. Dann kann der "counter" der Monitor sein.
Oder hab ich was übersehen?
 
Limdul hat dir die Fage eigentlich schon beantwortet. Was musst du synconisiren? Nicht die run Methode.
Auf welche variable darf immer nur einer zugreifen.
Wieviel instanzen von der counter variablen giebt es?
Das sind Fragen die dur dir stellen solltest.
 
Limdul hat dir die Fage eigentlich schon beantwortet.
Das habe ich doch auch so Programmiert und es geht. Nur steht in der Aufgabe leider das man keine neue Variable hinzufügen darf oder die Main Methode ändern darf. Das musste ich aber leider bei dieser Lösung. Zumindest muss ja eine Variable hinzugefügt werden z. B.
Java:
    private static final Object monitor = new Object();

Tipp versuche es doch mal mit einer static counter Variablen.
Oh sekunde gute Idee 😎
 
Nein leider geht es nicht.
Java:
public class Counter extends Thread {
    static Integer counter = 0;
    //private static final Object monitor = new Object();

    public Counter(String n) {
        super(n);
    }

    public void run() {
        while (counter < 1000) {
            synchronized(counter) { //synchronized(monitor) { geht (doch es ist eine Variable dazugekommen)
                System.out.print("Name: " + this.getName() + " ");
                increment();
                System.out.println(counter);
                increment();
            }
        }
    }

    private void increment() {
        counter++;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 5; i++)
            new Counter("" + i).start();
    }
}

Ahha okay das geht leider ebenfalls nicht, da

Synchronization should not be done on instances of value-based classes​

Java:
Noncompliant Code Example

private static final Boolean bLock = Boolean.FALSE;
private static final Integer iLock = Integer.valueOf(0);
private static final String sLock = "LOCK";
private static final List<String> listLock = List.of("a", "b", "c", "d");

public void doSomething() {

  synchronized(bLock) {  // Noncompliant
    // ...
  }
  synchronized(iLock) {  // Noncompliant
    // ...
  }
  synchronized(sLock) {  // Noncompliant
    // ...
  }
  synchronized(listLock) {  // Noncompliant
    // ...
  }
 
Deswegen meine Idee, mit der eigenen Klasse, für die "counter" Variable.
Ja das geht ;-)
Doch auf die Idee wäre ich so nie gekommen!
🙁

So würde es wohl laufen:
Java:
public class Counter extends Thread {
    static IntValue counter = new IntValue(0);
    
    public Counter(String n) {
        super(n);
    }

    public void run() {
        while (counter.getValue() < 1000) {
            synchronized(counter) {
                System.out.print("Name: " + this.getName() + " ");
                counter.increment();
                System.out.println(counter.getValue());
                counter.increment();
            }
        }
    }

    public static void main(String[] args) {
        for (int i = 0; i < 5; i++)
            new Counter("" + i).start();
    }
}

public class IntValue {
    static int value;
    
    public IntValue(int value) {
        this.value = value;
    }
    
    public void increment() {
        value++;
    }
    
    public int getValue() {
        return value;
    }
    
}
 
Eine weitere Idee wäre, auf dem Class Objekt der Klasse Counter zu synchronisieren, also:
Java:
public void run() {
  while (counter < 10000) {
    synchronized (Counter.class) {
      increment();
      System.out.println(counter);
      increment();
    }
  }
}
Das erfordert keinerlei zusätzliche Variablen. Der Trick ist nur, zu wissen, dass es solch ein Class-Objekt gibt.
 
Das hilft mir alles ungemein Danke
Eine weitere Idee wäre, auf dem Class Objekt der Klasse Counter zu synchronisieren, also:
Okay das läuft ebenfalls. Doch das hier verstehe ich leider überhaupt nicht sry.

Vorher bei static Datenelement (Objekt) ist dieses Objekt ja schon vorher da und wir sperren dieses über die Referenz und geben es erneut frei.
Bei der Lösung oben von @LimDul erstellen wir ein Objekt und geben dieses dem Konstruktor mit. Speichern die Referenz im jeweiligen Objekt und sperren dann durch die Referenz das Objekt, das in der Main erstellt wurde.

Doch was passiert bei Counter.class da komme ich jetzt überhaupt nicht mehr mit!
 
Doch was passiert bei Counter.class da komme ich jetzt überhaupt nicht mehr mit!
Der Ausdruck Counter.class wertet zu einem Objekt des Typs java.lang.Class aus und meint "diese Klasse" (als Objekt). Der hier verwendete Monitor ist letztlich exakt derselbe wie bei statischen Methoden dieser Klasse mit dem Schlüsselwort synchronized.
Also:
Java:
public static synchronized void methode() {...}
ist vom Verhalten her dasselbe wie:
Java:
public static void methode() {
  synchronized (Counter.class) {
    ...
  }
}
Du hast bei dir nur keine statische Methode und deswegen kannst du ein synchronized-Block mit dem Class-Objekt verwenden.
 
Java:
 synchronized static Integer counter = 0;
Sollte es sein. Somit kann imner nur einer auf die wapper Klasse zugreifen.
Und da es static ist gibt es sie auch nur einmal.
 
Java:
 synchronized static Integer counter = 0;
Sollte es sein. Somit kann imner nur einer auf die wapper Klasse zugreifen.
Und da es static ist gibt es sie auch nur einmal.
Nein. Siehe: https://www.java-forum.org/thema/counter-mit-ungeraden-zahlen.198543/#post-1318916
Du musst also ein Objekt beim synchronized verwenden, das in allen Objekten verwendet wird. Die erste Idee wäre, counter zu verwenden - das ist ja static, aber das wird leider auch nicht funktionieren, da counter++ in wirklichkeit ein neues counter Objekt erzeugt. (Autoboxing / Unboxing lässt grüßen).
 
Die counter Variable ist doch von Anfang an static. Es sollte also in allen 5 Threads die gleiche Instanz benutz werden. Auch nur eine geben auch wenn es mehrerer Objekte von der Klasse gibt.
Ja, am Anfang, bis der erste Thread counter++ ausführt. Ab dann machen alle Threads, was sie wollen, weil sie im Zweifel alle auf unterschiedliche Objekte synchronisieren für die nächsten Iterationen. Und, darüber hinaus hast du ja auch keine Garantie, dass alle Threads immer exakt gleichzeitig an jedem synchronized-Punkt pro Iteration ankommen.
Also: Du hast ja überhaupt keine Garantie, dass jeder Thread zu jedem Zeitpunkt immer dasselbe Objekt in der Variablen sieht. Dazu müsste die Variable auch noch final sein, was sie aber nicht ist.
 
Oder ein static synchronized getter von counter. Der dann benutzt wird.
Es nützt Dir doch nichts, den Getter zu synchronisieren. Dann kann nur ein Thread auf einmal den Getter Aufrufen, aber das machen 2 Threads hintereinander und beide addieren 1 ... und schreiben es zurück und damit ist dann von den 2 Mal erhöhen nur eins erfolgt.
 
Dieser Gesprächs-Thread hier ist ein perfektes Beispiel dafür, wie unfassbar schwer doch Multithreading mit Shared Memory tatsächlich ist, und wie schnell es unterschätzt wird bzw. wichtige Dinge übersehen werden können.
Danke. Genau so ist es, ich sortiere das ganze später mal ein und schau ob ich es wirklich richtig verstehe 🙂

Noch etwas anders. Hat jemand ein Ansatz für dieses Problem?
Gegeben ist folgende Klasse:
Java:
public class Lager extends Thread {
    private boolean vorhanden = false;
    private int paket;

    public synchronized int abholen() {
        if (vorhanden == true) {
            vorhanden = false;
            return paket;
        }
        
    }

    public synchronized void anliefern(int wert) {
        if (vorhanden == false) {
            vorhanden = true;
            paket = wert;
        }
    }
}

Bei dieser Implementierung von Lager gibt es das Problem, dass die Operation abholen() keinen Rückgabewert liefert, wenn kein Paket vorhanden ist und deshalb nicht übersetzt werden kann. Notwendig wäre, dass abholen() wartet, bis ein Paket angeliefert wird. Genauso schreibt anliefern() nur dann den übergebenen Wert in paket , wenn kein Paket vorhanden ist. Geben Sie modifizierte Versionen von abholen() und anliefern() an, so dass die Operationen anstelle der if Abfrage warten, bis sie durchgeführt werden können, keine Verklemmung auftreten kann und der Zugriff auf das Paket wechselseitig ausgeschlossen ist.
Mein erster gedanke war wieder mal simple doch das kann überhaupt nicht sein. Ich dachte bei dieser Aufgabe auf der Stelle an ein Erzeuger und Verbraucher System. Doch die Klasse Lager ist ebenfalls ein Thread und das verwirrt mich. Wenn es ein Erzeuger Verbraucher System wäre, könnte man ja das Lager als Buffer aufbauen also so:
Java:
public class Buffer {

    private boolean available = false;
    private int data;

    public synchronized void put(int x) {
        while (available) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
        data = x;
        available = true;
        notifyAll();
    }

    public synchronized int get() {
        while (!available) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
        available = false;
        notifyAll();
        return data;
    }
}

Das kann ja aber nicht sein weil Lager eben ein Thread sein soll und die run-Methode implementieren sollte dann. Somit müsste man das Lager ja schlafen legen und wer macht es wieder wach?
Wenn nicht erstelle ich dazu auch gerne erst mal ein eigenes Thema ;-)
 
Mein erster gedanke war wieder mal simple
Und das sieht doch auch gut aus. Ich denke, der Gedanke war prinzipiell schon goldrichtig. Nun bau es nur eben in die Methoden von Lager ein, denn das it ja die Aufgabe.

Das kann ja aber nicht sein weil Lager eben ein Thread sein soll und die run-Methode implementieren sollte dann.
Nein, Das extends Thread würde ich hier ehrlich gesagt nicht beachten. Es gibt keine run Methode und für die Funktionalität braucht es auch eine run Methode.

Wer oder was startet denn den Thread?
Wer ruft die beiten Methoden auf?
Das spielt doch für die Aufgabe keine Rolle. Es ist doch klar, was die Methoden machen sollen durch den vorhandenen Code und die Aufgabe.
 
Gut dann hätte ich nun zwei Lösungen. Ich dachte daran, was ist wenn es eine run Methode gibt. Wie müsste die dann aussehen um auf die Lösung der Aufgabe zu kommen. Das war dann wohl doch wieder um zu viele Ecken gedacht.

Also der erste Lösungsansatz wäre das extends Thread eben mehr oder weniger einfach zu vernachlässigen:
Java:
public class Lager extends Thread {
    private boolean vorhanden = false;
    private int paket;

    public synchronized int abholen() {
        while (!vorhanden) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
        vorhanden = false;
        notifyAll();
        return paket;
    }
    
    public synchronized void anliefern(int wert) {
        while (vorhanden) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
        paket = wert;
        vorhanden = true;
        notifyAll();
    }
}

Der zweite Ansatz wäre es eben als Erzeuger-Verbraucher System zu Modellieren (das dürfte aber wahrscheinlich gegen die Aufgabe verstoßen da dort ja nicht steht das die Klasse verändert werden darf (es sollen ja nur die zwei Methoden verändert werden)):
Java:
public class Lager2 extends Thread {

    private Buffer b;

    Lager2(Buffer b) {
        this.b = b;
    }

    public void anliefern(int wert) {
        b.put(wert);
    }

    public int abholen() {
        return b.get();
    }

}

Die Klasse Buffer ist die selbe wie oben die 😎
 
Ja, das Erste wäre auch, was ich als Lösung hier ansehen würde. Ein spezieller Thread ist hier nicht notwendig und eine zusätzliche run Methode wäre vermutlich auch nicht im Sinne der Aufgabe, die ja nur die Anpassung dieser beiden Methoden vorsieht:
Geben Sie modifizierte Versionen von abholen() und anliefern() an
 
Wer oder was startet denn den Thread?
Wer ruft die beiten Methoden auf?
Das verunsichert mich jetzt aber etwas.

Vielleicht gibt es noch eine weiter Lösung.
____
Ich hab nun mal zwei Klassen erstellt eine Producer und Consumer Klasse. Dort übergebe ich das von oben erstellte Lager und es klappt wie aus dem Lehrbuch.
Nun habe ich mich weiter gefragt, ist das extends Thread in der Lager Klasse nur Verwirrung oder vielleicht macht es auch anders Sinn.
So gesehen wäre Lager doch Producer und Consumer in einem wenn dort eine run Methode existieren würde. Gibt es ein solches "design pattern" in der Parallelen Entwicklung?

😵‍💫😵‍💫😵‍💫
 
Lass Dich einfach nicht verunsichern!

Ich hab nun mal zwei Klassen erstellt eine Producer und Consumer Klasse. Dort übergebe ich das von oben erstellte Lager und es klappt wie aus dem Lehrbuch.
Damit hast Du Deine Lösung sozusagen mit Hilfe eines Tests bestätigt. Das ist doch erst einmal eine super Sache!

Und bezüglich des extends Thread: hat das irgend eine Relevanz für die Aufgabe? Haben synchronized, wait und notify ein besonderes Verhalten, wenn diese in einer Instanz aufgerufen werden, die von Thread erbt? Thread könnte z.B. wait und notifyAll überschrieben haben. Aber Du hast es ja getestet - und da es funktioniert hat, scheint da nicht wirklich etwas zu sein, oder?
 

Zurück
Oben