# Bearbeiten eines Buchungssystems



## Pody (26. Jan 2019)

Hi Leute, also ich hab folgendes Problem: 
"Legen Sie im Package ledger eine Klasse mit dem Namen JournalEntryQueue an und realisieren Sie in ihr einen Zwischenspeicher für eine gegebene Anzahl an Buchungssätzen. Es müssen sich Buchungssätze hinzufügen lassen, der erste Buchungssatz muss herausgenommen werden können und die aktuelle Anzahl an Buchungssätzen im Zwischenspeicher muss ermittelt werden können."
Das ist der erste Teil der Aufgabenstellung eigentlich kann ich das alles aber ich verstehe scheinbar die Aufgabenstellung nicht. Ich weiß dass ich eine Queue erstellen soll und dafür die Collections verwenden soll. Ich habe jedoch ein ziemliches problem mit der Syntax weil ich echt nicht weiß wo ich anfangen soll.

Ich habe leider nurnoch bis Sonntag abend Zeit und komme kein Stück vorran, ihr würdet mir unendlich helfen wenn ihr mir helfen würdet diese Aufgabe zu lösen. Ich würde es sehr gerne verstehen und möchte keine einfachen lösungen.


----------



## httpdigest (26. Jan 2019)

Okay, fangen wir mal langsam an:


Pody hat gesagt.:


> eigentlich kann ich das alles aber ich verstehe scheinbar die Aufgabenstellung nicht


Was verstehst du daran genau nicht?


Pody hat gesagt.:


> Ich weiß dass ich eine Queue erstellen soll und dafür die Collections verwenden soll. Ich habe jedoch ein ziemliches problem mit der Syntax weil ich echt nicht weiß wo ich anfangen soll.


Weil du nicht weißt, wo du anfangen sollst, hast du ein Problem mit der Syntax? Was hast du denn schon?


----------



## Pody (26. Jan 2019)

Also Zuerst dachte ich wenn ich in meiner klasse eine passende Queue erstelle dann kann ich sie in einer anderen Klasse ganz normal per punktoperator aufrufen. Leider müsste ich ich sie dann static setzen und das funktioniert mit den schritten darauf nicht. Ich zeig dir am besten kurz was ich meine 

```
package ledger;

import java.util.LinkedList;
import java.util.Queue;

public class JournalEntryQueue {

    public Queue<String> journalEntryQueue = new LinkedList<String>();

}
```


```
@Override
    public void run() {
       
        if()
       

    }
```

Ich kann hier leider nur auf die Queue zugreifen wenn es sich um eine Klassen Variable handelt. 
Ich glaube wenn du die gesamte Aufgabenstellung siehst kann ich das besser erklären.

Aufgabe 11.1 – JournalEntryQueue Legen Sie im Package ledger eine Klasse mit dem Namen JournalEntryQueue an und realisieren Sie in ihr einen Zwischenspeicher für eine gegebene Anzahl an Buchungssätzen. Es müssen sich Buchungssätze hinzufügen lassen, der erste Buchungssatz muss herausgenommen werden können und die aktuelle Anzahl an Buchungssätzen im Zwischenspeicher muss ermittelt werden können. 

Aufgabe 11.2 – Accountant Erweitern Sie die Klasse Accountant indem Sie die Klasse entweder von der Klasse Thread erben lassen oder die Schnittstelle Runnable implementieren und in der entsprechenden run()-Methode folgende Funktionalität realisieren: 

1. Sind Buchungssätze im Zwischenspeicher vorhanden (siehe Aufgabe 11.1), dann nehme den ersten Buchungssatz heraus; sonst beende den Algorithmus. 
2. Probiere den Buchungssatz zu verbuchen (siehe postEntry()). 
3. Kann der Buchungssatz nicht verbucht werden, weil es einen Syntaxfehler oder es einen anderen unbehebbaren Fehler gibt (z.B. Konto nicht vorhanden, Soll-Betrag ungleich Haben-Betrag), soll der Buchungssatz verworfen werden. 
4. Kann der Buchungssatz zum aktuellen Zeitpunkt nicht verbucht werden (z.B. Konto bereits geöffnet), soll der Buchungssatz zurück in den Zwischenspeicher gelegt werden. 
5. Gehe zu 1. - 2 - Achten Sie bei Ihrer Lösung darauf, dass immer nur der Accountant-Thread auf ein Konto zugreift und dessen Beträge verändert, der dieses Konto auch geöffnet hat (Hinweis: Hierfür werden Sie auch andere Klassen erweitern/verändern müssen). Bedenken Sie auch Deadlocks und dessen Auflösung in Ihrem Algorithmus: Accountant A1 hat bereits Konto K1 geöffnet und möchte nun Konto K2 öffnen, A2 hat K2 geöffnet und möchte K1 öffnen. 

Aufgabe 11.3 – Main Verändern die Main-Methode wie folgt und testen Sie Ihren Algorithmus mit den Parameterwerten x={10.000, 100.000, 1.000.000} und y={1, 2, 5, 10}. Achten sie zudem darauf, dass die Konstante ERRORRATIO in der Klasse AccountManager auf 0 gesetzt ist um möglichst viele erfolgreiche Buchungen zu ermöglichen. 

1. Erstellen Sie ein Objekt der Klasse JournalEntryQueue und befüllen es mit x zufälligen Buchungssätzen. 
2. Starten Sie y Accountant-Threads, die die Buchungssätze abarbeiten. 
3. Warten Sie, bis sich alle Accoutant-Threads beendet haben und der Zwischenspeicher geleert ist. 
4. Geben Sie Anzahl der erfolgreich durchgeführten Buchungen und die dafür benötigte Gesamtlaufzeit (Hinweis: System.currentTimeMillis()) auf der Konsole aus, Bsp: „1000000 postings in 73903ms“. Erstellen Sie eine Tabelle mit Ihren Laufzeitergebnissen: 10.000 100.000 1.000.000 1 2 5 10


----------



## Pody (26. Jan 2019)

Als nächstes hatte ich die Idee dass ich meine Klasse von einem der Queues erben lasse, da ich ja dann auf die gleichen Methoden etc. der Queue zugreifen kann.

```
package ledger;

import java.util.concurrent.ConcurrentLinkedQueue;

public class JournalEntryQueue<E> extends ConcurrentLinkedQueue<E> {
    /**
     *
     */
    private static final long serialVersionUID = 1L;

}
```

Müsste ich dann im nächsten Schritt eine Queue instanzieren ?

```
public void run() {
        JournalEntryQueue<String> temp = new JournalEntryQueue<String>();
        if (temp.isEmpty()) {

        }

    }
```
Aber das würde ja keinen Sinn machen weil ich dann jedesmal eine neue Queue erstellen würde wenn ich die run methode aufrufe. Ansonsten dachte ich auch, dass ich eventuell eine Queue als Parameter übergeben soll um sie dann mit der Methode zu bearbeiten aber das geht auch nicht weil man ja die run Methode nicht überschreibt.


----------



## httpdigest (26. Jan 2019)

Ich würde schon die Queue/LinkedList wegkapseln, also eben entsprechende Methoden in die Klasse JournalEntryQueue hinzufügen, um die geforderten Operationen durchzuführen. Auch, wenn das bedeutet, dass diese eigentlich einfach nur an die interne Queue weiter delegieren. (btw.: Bist du sicher, dass du die Java Collections Klassen nutzen darfs, und das nicht selber implementieren sollst?)
Desweiteren würde ich jedem Accountant dann genau die eine Instanz der JournalEntryQueue als Konstruktorparameter mitgeben und dann halt in einer Instanzvariable im Accountant speichern, damit du dann eben in der run() Methode darauf zugreifen kannst.


----------



## Pody (26. Jan 2019)

Danke für deine Antwort, also ja in einer Mail wurde explizit nochmal gesagt dass wir Collections Klassen verwenden sollen. Wenn ich jetzt die geforderten Methoden erstelle wäre das ohne Collections oder ?


----------



## httpdigest (26. Jan 2019)

Pody hat gesagt.:


> Wenn ich jetzt die geforderten Methoden erstelle wäre das ohne Collections oder ?


Nein, das heißt es nicht. Du definierst auf deiner JournalEntryQueue Klasse nur die Methoden, die du für die Aufgabe brauchst.
Und intern innerhalb der JournalEntryQueue Klasse - sozusagen als Implementierungsdetail - verwendest du einfach eine tatsächliche java.util.Queue, meinetwegen mit java.util.LinkedList als konkrete Implementierung.


----------



## Pody (26. Jan 2019)

Wenn ich dann mit den erstellten Methoden auf die Queue zugreifen möchte, müsste ich sie erst static setzen oder? 

```
public class JournalEntryQueue {

    Queue<String> JournalEntryQueue = new LinkedList<String>();

    public String peek() {
        return JournalEntryQueue.peek();
    }

    public String poll() {
        return JournalEntryQueue.poll();
    }

    public int size() {
        return JournalEntryQueue.size();
    }

    public Boolean isEmpty() {
        return JournalEntryQueue.isEmpty();
    }

    public Boolean add(String journalEntry) {
        return JournalEntryQueue.add(journalEntry);
    }

}
```

so sieht jetzt mein JournalEntryQueue aus 


```
public void run() {
        if (JournalEntryQueue.isEmpty()) {

        }

    }
```
Wenn ich jetzt das hier machen will um zu kontrollieren ob die Queue leer ist krieg ich die meldung wieder dass das nicht funktioniert weil die methode nicht static ist.


----------



## httpdigest (26. Jan 2019)

Hach je. Du sollst _eine Instanz_ der Klasse JournalEntryQueue erzeugen und diese _Instanz_ benutzen. Instanzen einer Klasse erzeugt man mit `new`.


----------



## Pody (26. Jan 2019)

Tut mir leid dass ich mich so blöd anstelle . Ok wenn ich dann davor eine Instanz erstellt habe und die Methoden mit ihr verwende geht es darum dass trotzdem nur die Queue in der JournalEntryQueue Klasse verändert wird oder?


----------



## httpdigest (26. Jan 2019)

Schon okay.  Durch die _Instanz_methoden der JournalEntryQueue Klasse veränderst du die in der JournalEntryQueue Instanz gespeicherte _Instanz_ deiner Queue-Klasse (also LinkedList), ja, korrekt. Denn auch die Queue ist ja in einer _Instanz_variablen gespeichert, existiert also pro JournalEntryQueue-_Instanz_.


----------



## Pody (26. Jan 2019)

Ok ich hab jetzt fast die komplette 11.2 gemacht und so sieht meine run methode aus 

```
public void run() {
        JournalEntryQueue temp = new JournalEntryQueue();
        if (temp.isEmpty()) {
            return;
        } else {
            String journalEntry = temp.poll();
            try {
                postEntry(journalEntry);
            } catch (InvalidJournalEntryException e) {
                journalEntry = null;
                e.printStackTrace();
            } catch (AccountException e) {
                temp.add(journalEntry);
            }
            run();
        }

    }
```

"Achten Sie bei Ihrer Lösung darauf, dass immer nur der Accountant-Thread auf ein Konto zugreift und dessen Beträge verändert, der dieses Konto auch geöffnet hat (Hinweis: Hierfür werden Sie auch andere Klassen erweitern/verändern müssen). Bedenken Sie auch Deadlocks und dessen Auflösung in Ihrem Algorithmus: Accountant A1 hat bereits Konto K1 geöffnet und möchte nun Konto K2 öffnen, A2 hat K2 geöffnet und möchte K1 öffnen. " 

Hier soll ich wahrscheinlich die methoden in der JournalEntryQueue bearbeiten und Syncronized verwenden oder?


----------



## httpdigest (26. Jan 2019)

Es bringt nichts, wenn jeder Accountant seine eigene JournalEntryQueue Instanz in der run() Methode erzeugt. Die Übung dient doch dazu, Multithreading und Zugriff auf gemeinsame Ressourcen zu trainieren. Ich sagte bereits in einem früheren Post, dass du nur eine _einzige_ JournalEntryQueue Instanz erzeugen sollst und diese den Accountants am besten per Kontruktorparameter mitgeben und dort in einer Instanzvariablen speichern solltest.
Wenn du in der run() Methode eine neue JournalEntryQueue Instanz erzeugst, ist diese doch notwendigerweise _immer_ empty.
-> https://www.java-forum.org/thema/bearbeiten-eines-buchungssystems.183893/#post-1173815


----------



## Pody (26. Jan 2019)

Ok also so ? somit hat jedes Accountant ein und das selbe JournalEntryQueue.

```
public class Accountant implements Runnable {
    JournalEntryQueue Queue;
    public Accountant(JournalEntryQueue Queue) {
        this.Queue = Queue;
    }
```


```
public void run() {

        if (Queue.isEmpty()) {
            return;
        } else {
            String journalEntry = Queue.poll();
            try {
                postEntry(journalEntry);
            } catch (InvalidJournalEntryException e) {
                journalEntry = null;
                e.printStackTrace();
            } catch (AccountException e) {
                Queue.add(journalEntry);
            }
            run();
        }
```


----------



## Pody (26. Jan 2019)

Noch etwas 

```
public class JournalEntryQueue {

    Queue<String> JournalEntryQueue = new LinkedList<String>();

    public String peek() {
        return JournalEntryQueue.peek();
    }

    public String poll() {
        return JournalEntryQueue.poll();
    }

    public int size() {
        return JournalEntryQueue.size();
    }

    public Boolean isEmpty() {
        return JournalEntryQueue.isEmpty();
    }

    public Boolean add(String journalEntry) {
        return JournalEntryQueue.add(journalEntry);
    }
```
hier greife ich ja immer auf die JournalEntryQueue zu, ist das wirklich richtig?


----------



## mihe7 (28. Jan 2019)

Hinweis: in Java schreibt man Bezeichner von Variablen, Parametern und Methoden in lowerCamelCase, Typnamen (Namen von Klassen usw.) dagegen in UpperCamelCase. 



Pody hat gesagt.:


> somit hat jedes Accountant ein und das selbe JournalEntryQueue.


Die Aussage ist pauschal nicht richtig. Es hängt davon ab, wie Du die Accountant-Objekte erzeugst:

```
Accountant a1 = new Accountant(new JournalEntryQueue());
Accountant a2 = new Accountant(new JournalEntryQueue());
```
vs

```
JournalEntryQueue queue = new JournalEntryQueue();
Accountant a1 = new Accountant(queue);
Accountant a2 = new Accountant(queue);
```


----------

