Objektorientierte Programmiertechniken
LVA 185.A01, VU, 3 ECTS, 2015/2016 W
| Ausgabe: | 2.12.2015 |
| Abgabe: | 9.12.2015, 12:00 Uhr |
Für die Simulation wird der rechteckige Wald schachbrettartig in einzelne Felder aufgeteilt. Auf jedem Feld kann sich maximal eine gesunde Kolonie von Buchdruckern oder eine von Krankheitserregern befallene Kolonie befinden. Falls eines der 8 Nachbarfelder einer gesunden Kolonie frei ist, entsteht dort nach einer gewissen Zeit eine neue Kolonie. Falls bei so einer Neubesiedlung der Fall auftritt, dass eine gesunde Kolonie von 8 gesunden Nachbarkolonien umgeben ist, so wird diese mittlere Kolonie von Krankheitserregern befallen. Falls eine kranke Kolonie nach einer gewissen Zeit mindestens 2 gesunde Nachbarkolonien hat, dann werden gleichzeitig 2 Nachbarkolonien infiziert und daraus wird je eine kranke Kolonie. Die ursprüngliche kranke Kolonie stirbt dann ab, egal ob Nachbarkolonien infiziert wurden oder nicht. Das bedeutet, gesunde Kolonien bestehen ewig, kranke Kolonien bestehen nur eine kurze Zeit.
Simulieren Sie die Ausbreitung und das Absterben der Käferkolonien mittels eines nebenläufigen Java-Programms. Stellen Sie dabei jede Käferkolonie durch einen eigenen Thread dar. Jede Käferkolonie besiedelt nach einer gewissen Zeit (wenige Millisekunden zufallsgesteuert (5-50)) eine Nachbarzelle. Zählen Sie die Anzahl der Besiedlungsschritte einer Kolonie mit. Die neu entstandene Kolonie übernimmt dabei den Zählerstand der Ursprungskolonie. Simulieren Sie Wartezeiten mittels der Methode Thread.sleep(n). Achtung: sleep behält alle Monitore (= Locks); Sie sollten sleep daher nicht innerhalb einer synchronized-Methode oder -Anweisung aufrufen, wenn während der Wartezeit von anderen Threads aus auf dasselbe Objekt zugegriffen werden soll. Wenn eine Kolonie den maximalen Zählerstand (32) erreicht hat, oder alle Kolonien abgestorben sind, geben Sie von allen lebenden Kolonien den Zählerstand und die Position (auf welchem Feld sie sich befindet) aus und beenden alle Threads. Verwenden Sie Thread.interrupt() um einen Thread zu unterbrechen. Geben Sie die Position als X- und Y-Koordinate eines Feldes sowie den Zählerstand aus, und beenden Sie den Thread. Ein Wald darf in jeder Dimension (waagrecht und senkrecht) nicht mehr als 80 Felder haben. Geben sie immer, wenn sich eine Kolonie vervielfältigt hat, den Wald zeilenweise am Bildschirm aus. Verwenden Sie den Buchstaben "o" für ein Feld, das mit einer gesunden Kolonie belegt ist und den Buchstaben "x" für ein Feld, das mit einer kranken Kolonie belegt ist, zum Beispiel so:
x x
o o x x x x
o o o o
o o o o o o
o o o
Die Klasse Test soll (nicht interaktiv) Testläufe des Waldes durchführen und die Ergebnisse in allgemein verständlicher Form in der Standardausgabe darstellen. Bitte achten Sie darauf, dass die Testläufe nach kurzer Zeit terminieren (maximal 10 Sekunden für alle zusammen). Bitte achten Sie darauf, dass die Testläufe keine Systemlimits wie maximale Anzahl an gleichzeitig aktiven Threads auf dem Abgaberechner (g0) überschreiten. Führen Sie mindestens drei Testläufe mit unterschiedlichen Einstellungen durch:
Daneben soll die Datei Test.java wie gewohnt als Kommentar eine kurze, aber verständliche Beschreibung der Aufteilung der Arbeiten auf die einzelnen Gruppenmitglieder enthalten – wer was gemacht hat.
| Synchronisation richtig verwendet, auf Vermeidung von Deadlocks geachted, sinnvolle Synchronisationsobjekte gewählt, kleine Synchronisationsbereiche | 45 Punkte |
| Lösung wie vorgeschrieben und sinnvoll getestet | 20 Punkte |
| Zusicherungen richtig und sinnvoll eingesetzt | 15 Punkte |
| Geforderte Funktionalität vorhanden (so wie in Aufgabenstellung beschrieben) | 15 Punkte |
| Sichtbarkeit auf so kleine Bereiche wie möglich beschränkt | 5 Punkte |
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. Punkteabzüge gibt es für
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. Stellen Sie sicher, dass die maximale Anzahl an Threads und der maximale Speicher nicht überschritten werden. Dazu ist es sinnvoll, dass Sie im Threadkonstruktor explizit die Stackgröße mit einem kleinen Wert angeben (z.B. 16k).
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.