Bearbeiten eines Buchungssystems

Pody

Mitglied
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

Top Contributor
Okay, fangen wir mal langsam an:
eigentlich kann ich das alles aber ich verstehe scheinbar die Aufgabenstellung nicht
Was verstehst du daran genau 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.
Weil du nicht weißt, wo du anfangen sollst, hast du ein Problem mit der Syntax? Was hast du denn schon?
 

Pody

Mitglied
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
Code:
package ledger;

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

public class JournalEntryQueue {

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

}

Code:
@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

Mitglied
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.
Code:
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 ?
Code:
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

Top Contributor
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

Mitglied
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

Top Contributor
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

Mitglied
Wenn ich dann mit den erstellten Methoden auf die Queue zugreifen möchte, müsste ich sie erst static setzen oder?
Code:
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

Code:
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

Top Contributor
Hach je. Du sollst eine Instanz der Klasse JournalEntryQueue erzeugen und diese Instanz benutzen. Instanzen einer Klasse erzeugt man mit `new`.
 

Pody

Mitglied
Tut mir leid dass ich mich so blöd anstelle :rolleyes:. 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

Top Contributor
Schon okay. :) Durch die Instanzmethoden 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 Instanzvariablen gespeichert, existiert also pro JournalEntryQueue-Instanz.
 

Pody

Mitglied
Ok ich hab jetzt fast die komplette 11.2 gemacht und so sieht meine run methode aus
Code:
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

Top Contributor
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

Mitglied
Ok also so ? somit hat jedes Accountant ein und das selbe JournalEntryQueue.
Code:
public class Accountant implements Runnable {
    JournalEntryQueue Queue;
    public Accountant(JournalEntryQueue Queue) {
        this.Queue = Queue;
    }

Code:
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

Mitglied
Noch etwas
Code:
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

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

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:
Java:
Accountant a1 = new Accountant(new JournalEntryQueue());
Accountant a2 = new Accountant(new JournalEntryQueue());
vs
Java:
JournalEntryQueue queue = new JournalEntryQueue();
Accountant a1 = new Accountant(queue);
Accountant a2 = new Accountant(queue);
 

Neue Themen


Oben