|
Ueb W2
|
Zielsetzung: Kennenlernen und Anwenden der Java-Synchronisationskonstrukte synchronized, wait, notify und notifyAll.
Beantworten Sie bitte diese Fragen, bevor Sie zu den praktischen Übungen übergehen.
'Variante 1: in Klasse Konto:'
public synchronized void veraendereWert( int delta ) {
this.wert += delta;
}
... und in Klasse KontoThread:
private void erhoeheKontostand() {
myKonto.veraendereWert(1);
totalInc = totalInc + 1;
}
'Variante 2: '
public void veraendereWert( int delta ) {
this.wert += delta;
}
private void erhoeheKontostand() {
synchronized( myKonto ) {
myKonto.veraendereWert( 1 );
}
totalInc = totalInc + 1;
}
3a) Warum ist die Variante 2 weniger "sicher" als die Lösung 1?
3b) Welches ist das (versteckte) Lock-Objekt, das in Variante 1 gehalten wird?
Wir haben in der Vorlesung gesehen, dass die folgende Konto-Klasse "thread-safe" ist, da alle public-Methoden als "synchronized" implementiert sind.
class Konto { // als Monitor konzipiert
private int id;
private int kontoStand = 0;
public Konto(int id, int initialBetrag) {
this.id = id; this.kontoStand = initialBetrag;
}
public int getId() {
return id;
}
public synchronized int getKontoStand () {
return kontoStand;
}
public synchronized void setKontoStand(int betrag) {
this.kontoStand=betrag;
}
public synchronized void veraendereKontoStand (int delta) {
this.kontoStand += delta;
}
}
Ein SW-Entwickler der noch nicht viel von Synchronisation gehört hat, implementiert, aufbauend auf der Klasse Konto, eine Operation für den Transfer eines Geldbetrages zwischen zwei Konti.
Die Klasse KontoUebertragThread implementiert dazu die Methode kontoTransfer (siehe Testprogramm KontoUebertragTest.java). Das Testprogramm erzeugt mehrere Threads, die teilweise auf denselben Konto-Objekten operieren.
class KontoUebertragThread extends Thread {
/* Betrag vom Konto vonKonto zum Konto nach Konto uebertragen */
public void kontoTransfer() {
if (vonKonto.getKontoStand() > betrag) { //Konto darf nicht ueberzogen werden
vonKonto.veraendereKontoStand(-betrag);
nachKonto.veraendereKontoStand(betrag);
totalInc += betrag;
}
}
}
Vorlagen
In dieser Aufgabe sollen Sie die Funktionsweise einer Ampel und deren Nutzung nachahmen.
Benutzen Sie die Vorgabe AmpelBetrieb.java.
Natürlich darf das Auto erst dann eine Ampel passieren, wenn diese auf grün ist! Für die Simulation der Zeitspanne fürs Passieren können Sie die folgende Anweisung verwenden:
sleep((int)(Math.random() * 500));
a) Falls Sie bei der Implementierung der Klasse Ampel die Methode notifyAll benutzt haben: Hätten Sie statt notifyAll auch die Methode notify verwenden können oder haben Sie notifyAll unbedingt gebraucht? Begründen Sie Ihre Antwort!
b) Falls Sie bei der Implementierung der Klasse Ampel die Methode notify benutzt haben: Begründen Sie, warum Sie notifyAll nicht unbedingt gebraucht haben!
'Bemerkung zur Vorgabe: Der Einfachheit halber sind alle Klassen in einer Datei zusammengefasst. Natürlich steht es ihnen frei, die Klassen auf mehrere Dateien aufzuteilen.'
Vorlagen
Zielsetzung: Umgang mit den Synchronisationsmöglichkeiten von Java Mutual Exclusion und Condition Synchronisation.
1. Producer- und Consumer-Thread Vorgegeben ist eine Implementation eines zirkulären Buffers. IBuffer ist in der Datei IBuffer.java und CircularBuffer in der Datei CircularBuffer.java implementiert. Als erstes soll ein "Producer" und ein "Consumer" implementiert werden. Unten ist das Gerüst dieser abgebildet:
class Producer extends Thread {
public Producer(String name, IBuffer buffer, int prodTime) {
...
}
public void run() {
...
}
}
class Consumer extends Thread
{
public Consumer(String name, IBuffer buffer, int consTime) {
...
}
public void run() {
...
}
}
Der Producer soll Daten in den Buffer einfüllen und der Consumer soll Daten herausholen. Auf den Buffer soll nur über das Interface zugegriffen werden. Das Zeitintervall, in dem Producer Daten einfüllen kann mit sleep((int)(Math.random() * prodTime)). Die Zeit fürs konsumieren können Sie entsprechend mit sleep((int)(Math.random() * consTime)) bestimmen.
Für Producer und Consumer wurde bereits ein Testprogramm CircBufferTest.java geschrieben:
Testen Sie nun damit ihre Consumer-, und Producer-Klassen. Versuchen sie den generierten Output auf der Console richtig zu interpretieren! Spielen sie mit den Zeitintervallbereichen von Producer (maxProdTime) und Consumer (maxConsTime) und ziehen sie Schlüsse. Erstellen sie über die Modifikation von prodCount und consCount mehrere Producer bzw Consumer. Tip: Generieren sie in den selber implementierten Klassen keine eigene Ausgabe. Ändern sie den bestehenden Code nicht.
Tipp: Verwenden Sie den Java Monitor des GuardedCircularBuffer-Objektes! Wenn die Klasse fertig implementiert ist, soll sie in der "CircBufferTest" Klasse verwendet werden.
Beantworten Sie genau eine der folgenden Fragen:
a) Falls Sie bei der Implementierung der Klasse GuardedCircularBuffer die Methode notifyAll benutzt haben: Hätten Sie statt notifyAll auch die Methode notify verwenden können oder haben Sie notifyAll unbedingt gebraucht? Begründen Sie Ihre Antwort!
b) Falls Sie bei der Implementierung der Klasse GuardedCircularBuffer die Methode notify benutzt haben: Begründen Sie, warum Sie notifyAll nicht unbedingt gebraucht haben!
Vorlagen
|
Ueb W2 |
|