Übungsblatt 13

Werbung
LehrstuhlfürBioinformatik
EinführungindieProgrammierungfürBioinformatiker
Prof.B.Rost,Dr.L.Richter
Blatt13
30.1.2017
ThreadsII
Aufgabe13.1.SynchronisiertesLesenundSchreiben
BetrachtenSiefolgendesProgramm:
public class TimesTwo implements Runnable {
private final SyncNumber n;
public TimesTwo(SyncNumber c) {
n = c;
}
@Override
public void run() {
int i = n.read();
n.write(i * 2);
System.out.println("write " + i * 2);
}
public static void main(String[] args) {
SyncNumber n = new SyncNumber();
TimesTwo d1 = new TimesTwo(n);
TimesTwo d2 = new TimesTwo(n);
new Thread(d1).start(); // Thread 1
new Thread(d2).start(); // Thread 2
}
}
DieKlasseSyncNumberistdabeigegebendurch:
public class SyncNumber {
private int c = 1;
public synchronized int read() {
return c;
}
public synchronized void write(int c) {
this.c = c;
}
}
GebenSiezwei(verschiedene)möglicheKonsolenausgabendesProgrammsan
undfüllenSiefürjedendieserProgrammdurchläufedieTabelleuntenaus.Jede
ZeilestehtfüreinenZeitschrittunddarfdaherauchnurgenaueinenEintrag
enthalten.AlsEinträgesindausschließlichfolgendeerlaubt:
• d1.run:Enter / d1.run:Returnanalogfürd2
• n.read:Enter / n.read:Return
• n.write:Enter / n.write:Return
• n.lock:Enter / n.lock:Return
• n.unlock()
• println(txt)
DabeibedeutendieEinträgefolgendes:
• x.foo:Entergibtan,dassdieMethodefooaufdemObjektx
aufgerufenwurde.DasPendantx.foo:Returngibtan,dassderAufruf
zumAufruferzurückkehrt.
• x.lock:EnterversuchtdasLockaufdemObjektxzuakquirieren.Das
Pendantx.lock:Returngibtan,dassdasLockakquiriertwurde.
• x.unlock()gibtdasLockaufdemObjektxfrei(diesisteine
KurzschreibweisefürdiezweikonsekutivenKommandos
x.unlock:Enter; x.unlock:Return).
• println(txt)gibtan,dassderStringtxtviaeinem
System.out.println()-AufrufaufderKonsoleausgegebenwird.
D.h.txtenthältkeineVariablenodernochauszuwertendeAusdrücke.
Wirdeinesynchronized-MethodemitdemNamenfoovondemObjektx
aufgerufen,sowirderstx.foo:EnterausgeführtunddanndasjeweiligeLock
x.lock:Enterakquiriert.DenAufrufSystem.out.println(String
txt)könnenSiedurchprintln()darstellen.
ProgrammdurchlaufVariante1
Thread1
Thread2
d1.run:Enter
d2.run:Enter
AusgabeaufderKonsole:
_____________________________
_____________________________
ProgrammdurchlaufVariante2
Thread1
Thread2
d1.run:Enter
d2.run:Enter
AusgabeaufderKonsole:
_____________________________
_____________________________
Aufgabe13.2.IteratorsummetrischerStack
ErgänzenSiedieKlasseSymmetricStackvonAufgabenblatt8umeinen
Iterator.DazusolldieKlassedasInterfaceIterable<Integer>
implementieren,d.h.dieKlassemussumeineMethodepublic
Iterator<Integer> iterator()ergänztwerden.VerwendenSiefürdiese
MethodedasfolgendeProgrammgerüst:
@Override
public Iterator<Integer> iterator(){
return new Iterator<Integer(){
//TODO
};
}
DerIteratorsollalsoineineranonymenKlasseimplementiertwerden,diedas
InterfaceIterator<Integer>implementiert.SiebrauchenimIteratornur
diebeidenMethodenhasNext()undnext(),nichtjedochdieoptionale
Methoderemove()implementieren.AchtenSiedarauf,dassdienext-Methode
eineNoSuchElementExceptionwirft,wenneskeineweiterenElementegibt,
vgl.https://docs.oracle.com/javase/8/docs/api/java/util/Iterator.html#next--.
Aufgabe13.3.ConcurrentModificationException
InderVorlesungwurdenIteratorenvorgestellt.DieJavaStandardbibliothek
stelltfürdieImplementierungvonIteratorenzweiInterfaceszurVerfügung:Das
InterfaceIterator<E>,siehe
https://docs.oracle.com/javase/8/docs/api/java/util/Iterator.htmlfürden
IteratorunddasInterfaceIterable<T>,siehe
https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.htmlfür
Datenstrukturen,dieeinenIteratorzurVerfügungstellen.Fürdiese
DatenstrukturenkanndieKurzschreibweisefürfor-Schleifenverwendet
werden.Beispiel:AlleCollectionsderJavaStandardbibliothekimplementieren
dasInterfaceIterable<T>,stellenalsoeinenIteratorzurVerfügung.Dieser
wirdbeiderfolgendenKurzschreibweiseverwendet:
LinkedList<Integer> list = new LinkedList<>();
// add some elements to list
for(int tmp : list)
System.out.println(tmp + " ");
Alternativ kann man auch direkt mit dem Iterator über die Liste iterieren. Dafür
stehen die Methoden hasNext() und next() zur Verfügung.
LinkedList<Integer> list = new LinkedList<>();
// add some elements to list
for(Iterator<Integer>it = list.iterator(); it.hasNext();)
System.out.println(it.next() + " ");
Möchte man nicht nur über eine Liste iterieren sondern diese auch gleichzeitig
modifizieren, darf man das nur über Methoden, die vom Iterator selbst zur
Verfügunggestelltwerden.DerlistIteratorderKlasseListimplementiert
das Interface ListIterator<E> und stellt deshalb einige Funktionen zur
Modifizierung einer Liste (add(E e), remove()) zur Verfügung, siehe
https://docs.oracle.com/javase/8/docs/api/java/util/ListIterator.html.
VerändertmanjedocheineListeanderweitig,währendmanmiteinemIterator
über diese iteriert, wird eine ConcurrentModificationException
geworfen,
siehe
https://docs.oracle.com/javase/8/docs/api/java/util/
ConcurrentModificationexception. html. Probieren Sie das mit dem folgenden
Codeaus:
LinkedList<Integer> list = new LinkedList<>();
for(int i = 0; i < 20; i++)
list.add(i);
for (int tmp : list) {
System.out.print(tmp + " ");
list.remove(tmp); //ConcurrentModificationException }
Prinzipiellsolltemansichdeshalbmerken,dassmaneineListenichtanderweitig
modifiziert während man mit einem Iterator darüber iteriert! Für
Modifikationen kann man auf die vom Iterator zur Verfügung gestellten
Methoden zurückgreifen. Insbesonder sollte man sich auch nicht auf eine
ConcurrentModificationException verlassen, da es bestimmte
Konstellationengibt,indenenkeineConcurrentModificationException
geworfen wird und der Iterator dann nicht vorhersehbares Verhalten zeigt.
ProbierenSiedazudenfolgendenCodeaus:
LinkedList<Integer> list = new LinkedList<>();
for(int i = 0; i < 20; i++)
list.add(i);
System.out.println(list);
int i = 0;
for(int tmp : list){
System.out.print(tmp + " ");
i++;
if(i > 18)
list.remove(0);
}
System.out.println("\n" + list);
Herunterladen