Objektorientierte Programmierung
LVA 185.162, VL 2.0, 2008 W
8. Übungsaufgabe
Themen:
nebenläufige Programmierung, Exceptions
Termine:
| Ausgabe: |
04.12.2008, 12:45 Uhr |
| reguläre Abgabe: |
11.12.2008, 12:45 Uhr |
| nachträgliche Abgabe: |
18.12.2008, 12:45 Uhr |
Abgabeverzeichnis:
Gruppe/Aufgabe8
Programmaufruf:
java Test
Grundlage:
Skriptum bis Seite 149
Aufgabe
Welche Aufgabe zu lösen ist:
Eine Fabrik erzeugt Essstäbchen in mehreren Verarbeitungsschritten:
Zuerst spaltet eine Zerteilmaschine ein Stück Holz in 10 rohe Stäbchen.
Diese werden von einer Schleifmaschine einzeln geglättet.
Je zwei Stäbchen werden anschließend durch eine Verpackungsmaschine in eine Packung verpackt.
In der Fabrik gibt es eine Zerteilmaschine, 5 Schleifmaschinen und 2 Verpackungsmaschinen.
Zwischen der Zerteilmaschine und den Schleifmaschinen gibt es einen Behälter für die rohen Stäbchen, zwischen den Schleifmaschinen und den Verpackungsmaschinen einen Behälter für die geschliffenen Stäbchen und nach den Verpackungsmaschinen einen Behälter für die verpackten Stäbchenpaare.
Wenn ein Behälter voll ist, müssen die betroffenen Maschinen so lange warten, bis im Behälter wieder genug Platz ist, um etwas hineinzulegen.
Es gibt einen Notstopp, der alle Maschinen gleichzeitig abschaltet.
Simulieren sie die Fabrik mittels eines nebenläufigen Java-Programms, wobei Maschinen und Behälter durch je einen Thread dargestellt werden.
Die Aufgabe der Simulation besteht darin, die von der Zerteilmaschine zerteilten Holzstücke, von jeder einzelnen Schleifmaschine geglätteten Stäbchen und von jeder Verpackungsmaschine erzeugten Packungen zu zählen.
Jede Maschine benötigt eine gewisse Arbeitszeit für jeden Arbeitsschritt.
Simulieren Sie diese Zeit mittels der Methode Thread.sleep(n) auf dem Thread, der die Maschine darstellt.
Lassen Sie jede Maschine einige Millisekunden arbeiten (simuliert durch schlafen, für jede Maschine unterschiedlich, z.B. zwischen 1 und 50 Millisekunden).
Simulieren Sie den Notstopp mittels eines Aufrufs der Methode Thread.interrupt() für jeden Thread.
Dabei sollen alle Maschinen (Threads) gestoppt und die Anzahl der bisher von den einzelnen Maschinen verarbeiteten Holzstücke, Stäbchen ud Packungen sowie der sich gerade in den einzelnen Behältern befindlichen Stäbchen und Packungen auf der Standardausgabe angezeigt werden.
Die Zerteilmaschine wird mit einer fixen Anzahl an Holzstücken gestartet.
Nachdem das gesamte Material verarbeitet wurde, sollen die Threads für die Maschinen und Behälter automatisch stoppen und (ebenso wie nach einem Notstopp) die Anzahl der verarbeiteten bzw. sich in den Behältern befindenden Holzstücke, Stäbchen und Packungen ausgeben.
Die Klasse Test soll die wichtigsten Normal- und Grenzfälle überprüfen und die Ergebnisse in allgemein verständlicher Form in der Standardausgabe darstellen.
Bitte achten Sie darauf, dass der Test nach kurzer Zeit von selbst terminiert - maximal 10 Sekunden.
Zumindest die folgenden Überprüfungen sind durchzuführen:
- Testen Sie die Simulation mit mindestens drei unterschiedlichen Verarbeitungsläufen.
- Testen Sie die Simulation in den verschiedenen Verarbeitungläufen mit unterschiedlichen Werten für die Arbeitszeiten der Maschinen, und geben Sie dabei auch Maschinen der selben Art unterschiedliche Arbeitszeiten.
- Testen Sie auch mit verschiedenen Behältergrößen.
Nehmen Sie so kleine Werte für die Behältergrößen an, dass zumindest bei einem Durchlauf Maschinen warten müssen, bis Platz in einem Behälter frei wird.
Der Behälter für die verpackten Stäbchen soll aber alle aus dem verfügbaren Material erzeugbaren Stäbchen aufnehmen können.
Warum die Aufgabe diese Form hat:
Die Fabrik soll die nötige Synchronisation bildlich veranschaulichen und durch die Analogie zur
realen Welt
ein Gefühl für die vielen eventuell auftretenden Sonderfälle geben.
Beispielsweise müssen die Maschinen erkennen, wann sie nach erledigter Arbeit stoppen sollen.
Einen speziellen Sonderfall stellt der Notstopp dar, der jederzeit in jedem beliebigen Zustand auftreten kann.
Dabei wird auch geübt, nach einer an einer beliebigen Programmstelle auftretenden Exception den Objektzustand so weit wie nötig zu rekonstruieren, um ein sinnvolles Ergebnis zurückliefern zu können.
Was im Hinblick auf die Beurteilung zu beachten ist:
Der Schwerpunkt bei der Beurteilung liegt auf korrekter nebenläufiger Programmerierung und der richtigen Verwendung von Synchronisation sowie dem damit in Zusammenhang stehenden korrekten Umgang mit Exceptions.
Kräftige Punkteabzüge gibt es für
- fehlende oder fehlerhafte Synchronisation,
- zu große Synchronisationsbereiche, durch die sich Threads gegenseitig unnötig behindern,
- nicht richtig abgefangene Exceptions im Zusammenhang mit nebenläufiger Programmerierung,
- Nichttermination nach 10 Sekunden,
- unnötigen Code und mehrfache Vorkommen gleicher oder ähnlicher Code-Stücke (wie z.B. mehrere Klassen für Behälter)
- vermeidbare Warnungen des Compilers, die mit (der falschen Verwendung von) Generizität in Zusammenhang stehen,
- Verletzungen des Ersetzbarkeitsprinzips bei Verwendung von Vererbungsbeziehungen,
- und mangelhafte Funktionalität des Programms.
Punkteabzüge gibt es unter anderem auch für mangelhafte Zusicherungen, schlecht gewählte Sichtbarkeit und unzureichendes Testen.
Wie die Aufgabe zu lösen ist:
Überlegen Sie sich genau, wie und wo Sie Synchronisation verwenden.
Halten Sie die Granularität der Synchronisation möglichst klein, um unnötige Beeinflussungen anderer Threads zu reduzieren.
Beachten Sie dabei auch, dass ein Aufruf von
sleep innerhalb einer synchronized-Methode oder synchronized-Anweisung den entsprechenden Lock nicht freigibt.
Für die Simulation einer Maschine ist das erwünscht, da die Maschine während eines Arbeitsschritts nichts anderes machen können soll.
An anderen Programmstellen ist ein derartiges Verhalten aber meist unerwünscht.
Testen Sie Ihre Lösung bitte rechtzeitig auf der g0, da es im Zusammenhang mit Nebenläufigkeit große Unterschiede zwischen den einzelnen Plattformen geben kann.
Ein Programm, das auf einem Rechner problemlos funktioniert, kann auf einem anderen Rechner (durch winzige Unterschiede im zeitlichen Ablauf) plötzlich nicht mehr funktionieren.
Dieser Indeterminismus macht das Testen nebenläufiger Programme äußerst schwierig.
Nebenläufigkeit kann die Komplexität eines Programms gewaltig erhöhen.
Achten Sie daher besonders darauf, dass Sie den Programm-Code so klein und einfach wie möglich halten.
Jede unnötige Anweisung kann durch zusätzliche Synchronisation (oder auch fehlende Synchronisation) eine versteckte Fehlerquelle darstellen und den Aufwand für die Fehlersuche um vieles stärker beeinflussen als in einem sequentiellen Programm.