Hier finden sich die besprochenen Java Programme des Sommersemesters 2009 ohne weiteren Kommentar.
Beispiel: Kontenverzeichnis, ohne generische Typen
import java.util.HashMap; import java.util.Map; public class KontenObject { // keys = integer, values = double private Map konten; public KontenObject() { konten = new HashMap(); } public double buchen(int n, double b){ double s = 0.0; double w = 0.0; Object ow = konten.get(n); if ( ow != null ) { w = (Double) ow; } s = w + b; konten.put(n,s); return s; } public double stand(int n) { Object ow = konten.get(n); if ( ow != null ) { return (Double) ow; } else { return 0.0; } } }
Beispiel:
public class KontenObjectTest { public static void main(String[] args) { KontenTypen bank = new KontenTypen(); bank.buchen(13,0.0); bank.buchen(11,0.0); System.out.println("bank(anfang) = " + bank); bank.buchen(13, 20.0); bank.buchen(11,-20.0); bank.buchen(17, 2.0); System.out.println("bank(ende) = " + bank); } public static void nomain(String[] args) { KontenObject bank = new KontenObject(); bank.buchen(13,0.0); bank.buchen(11,0.0); System.out.println("stand(13) = " + bank.stand(13)); System.out.println("stand(11) = " + bank.stand(11)); bank.buchen(13, 20.0); bank.buchen(11,-20.0); System.out.println("stand(13) = " + bank.stand(13)); System.out.println("stand(11) = " + bank.stand(11)); } }
Beispiel: Kontenverzeichnis mit generischen Datenypen
import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.TreeMap; public class KontenTypen { // keys = integer, values = double // festlegung: keys haben typ Integer // values haben typ Double private Map<Integer,Double> konten; public KontenTypen() { //konten = new HashMap<Integer,Double>(); konten = new TreeMap<Integer,Double>(); } public double buchen(int n, double b){ double s = 0.0; double w = 0.0; Double ow = konten.get(n); // jetzt als typ if ( ow != null ) { w = ow; // kein cast mehr notwendig } s = w + b; konten.put(n,s); return s; } public double stand(int n) { Object ow = konten.get(n); if ( ow != null ) { return (Double) ow; } else { return 0.0; } } // Prüfung, ob die Summe aller Stände 0.0 ist public boolean pruefe() { Collection<Double> werte = konten.values(); double summe = 0.0; for ( Double w : werte ) { // for statt Iterator summe += w; } if ( Math.abs(summe) <= 1.0E-10 ) { // wegen Rundungsfehler kein summe == 0.0 return true; } else { return false; } } public String toString(int n) { String s = "<Konto "; s += "nr='" + n + "'"; s += " stand='" + stand(n) + "'"; s += " />"; return s; } public String toString() { String s = "\n<Konten geprueft='" + pruefe() + "' >\n"; // hole alle Schlüssel aus der Abbildung Set<Integer> nummern = konten.keySet(); //s += nummern + "\n"; // hole was für die Schleife // 1. einen Iterator Iterator<Integer> it = nummern.iterator(); // 2. hole Schlüssel mit next() while ( it.hasNext() ) { Integer i = it.next(); s += toString(i) + "\n"; } s += "</Konten>\n"; return s; } }
Beispiel: Version mit List statt Set
import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; public class KontenTypen { // keys = integer, values = double // festlegung: keys haben typ Integer // values haben typ Double private Map<Integer,Double> konten; public KontenTypen() { //konten = new HashMap<Integer,Double>(); konten = new TreeMap<Integer,Double>(); } public double buchen(int n, double b){ double s = 0.0; double w = 0.0; Double ow = konten.get(n); // jetzt als typ if ( ow != null ) { w = ow; // kein cast mehr notwendig } s = w + b; konten.put(n,s); return s; } public double stand(int n) { Object ow = konten.get(n); if ( ow != null ) { return (Double) ow; } else { return 0.0; } } // Prüfung, ob die Summe aller Stände 0.0 ist public boolean pruefe() { //Collection<Double> werte = konten.values(); // will List<Double> haben List<Double> werte = new ArrayList<Double>(); werte.addAll( konten.values() ); double summe = 0.0; for ( Double w : werte ) { // for statt Iterator summe += w; } if ( Math.abs(summe) <= 1.0E-10 ) { // wegen Rundungsfehler kein summe == 0.0 return true; } else { return false; } } public String toString(int n) { String s = "<Konto "; s += "nr='" + n + "'"; s += " stand='" + stand(n) + "'"; s += " />"; return s; } public String toString() { String s = "\n<Konten geprueft='" + pruefe() + "' >\n"; // hole alle Schlüssel aus der Abbildung Set<Integer> nummern = konten.keySet(); //s += nummern + "\n"; // hole was für die Schleife // 1. einen Iterator Iterator<Integer> it = nummern.iterator(); // 2. hole Schlüssel mit next() while ( it.hasNext() ) { Integer i = it.next(); s += toString(i) + "\n"; } s += "</Konten>\n"; return s; } }
Beispiel: mit eigener Klasse für einen Konto-Datensatz
import java.util.Date; public class KontenRecord { String inhaber; double ueberziehungsKredit; Date datum; double stand; int konditionen; String bemerkungen; // constructor wird immer gebraucht public KontenRecord( String inhaber, double kredit, int kond, double stand, String bem ) { this.inhaber = inhaber; this.ueberziehungsKredit = kredit; this.konditionen = kond; this.stand = stand; this.bemerkungen = bem; this.datum = new Date(); } public void buche(double b) { stand += b; } // wird immer gebraucht public String toString() { String s = "<Record>\n"; s += "<Inhaber>" + inhaber + "</Inhaber>\n"; s += "<Stand>" + stand + "</Stand>\n"; // Aufgabe: die restlichen Info angeben s += "</Record>\n"; return s; } }
Beispiel:
import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.TreeMap; public class KontenMitRecord { // keys = integer, values = double // festlegung: keys haben typ Integer // values haben typ KontenRecord private Map<Integer,KontenRecord> konten; public KontenMitRecord() { //konten = new HashMap<Integer,KontenRecord>(); konten = new TreeMap<Integer,KontenRecord>(); } public double buchen(int n, double b){ KontenRecord ow = konten.get(n); // jetzt als typ if ( ow != null ) { ow.buche(b); konten.put(n,ow); } return ow.stand; } public double stand(int n) { KontenRecord ow = konten.get(n); if ( ow != null ) { return ow.stand; } else { return 0.0; } } // Prüfung, ob die Summe aller Stände 0.0 ist public boolean pruefe() { Collection<KontenRecord> werte = konten.values(); double summe = 0.0; for ( KontenRecord w : werte ) { // for statt Iterator summe += w.stand; } if ( Math.abs(summe) <= 1.0E-10 ) { // wegen Rundungsfehler kein summe == 0.0 return true; } else { return false; } } public String toString(int n) { String s = "<Konto "; s += "nr='" + n + "' >\n"; s += konten.get(n); // toString() s += "</Konto>"; return s; } public String toString() { String s = "\n<Konten geprueft='" + pruefe() + "' >\n"; // hole alle Schlüssel aus der Abbildung Set<Integer> nummern = konten.keySet(); //s += nummern + "\n"; // hole was für die Schleife // 1. einen Iterator Iterator<Integer> it = nummern.iterator(); // 2. hole Schlüssel mit next() while ( it.hasNext() ) { Integer i = it.next(); s += toString(i) + "\n"; } s += "</Konten>\n"; return s; } public void neuesKonto(int i, KontenRecord m) { if ( konten.get(i) != null ) { throw new IllegalArgumentException("Konto gibt es schon"); } konten.put(i,m); } }
Beispiel:
public class KontenObjectTest { public static void main(String[] args) { KontenMitRecord bank = new KontenMitRecord(); System.out.println("bank(anfang) = " + bank); KontenRecord maier = new KontenRecord( "Ingo Maier", 0.0, 1, 0.0, "keine" ); KontenRecord king = new KontenRecord( "Helmut King", 0.0, 1, 0.0, "keine" ); bank.neuesKonto(17,maier); bank.neuesKonto(4711,king); bank.buchen(17, 20.0); bank.buchen(4711,-20.0); System.out.println("bank(ende) = " + bank); } }
Es folgen einige weitere Ideen für Programmier-Aufgaben und Projekte.
Schreiben Sie KontenObject
mit Typ-Paramtern für die
Map
Datenstruktur um.
Das Ergebniss sollte wie KontenTypen
aussehen.
Schreiben Sie KontenTypen
so um, dass List
anstelle von
Set
und Collection
verwendet wird.
Lesen Sie dazu die Java API Dokumentation des Packets java.util
.
Nochmal gestellt für toString()
.
Vervollständigen Sie toString()
von KontenRecord
.
Beispiel: Ein- und Ausgabe von Konten-Objekten in Dateien.
import java.io.ObjectInputStream; import java.io.FileInputStream; import java.io.IOException; public class ObjectEinlesen extends ObjectInputStream { public ObjectEinlesen(String dateiName) throws IOException { super( new FileInputStream(dateiName) ); } }
Beispiel:
import java.io.ObjectOutputStream; import java.io.FileOutputStream; import java.io.IOException; public class ObjectAusgabe extends ObjectOutputStream { public ObjectAusgabe(String name) throws IOException { super( new FileOutputStream(name) ); } }
Beispiel:
import java.io.Serializable; import java.util.Date; public class KontenRecord implements Serializable { // Rest ist gleich }
Beispiel:
import java.io.IOException; import java.io.PrintWriter; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.TreeMap; public class KontenMitRecord { // keys = integer, values = double // festlegung: keys haben typ Integer // values haben typ KontenRecord private Map<Integer,KontenRecord> konten; public KontenMitRecord() { //konten = new HashMap<Integer,KontenRecord>(); konten = new TreeMap<Integer,KontenRecord>(); } public int size() { return konten.size(); } public double buchen(int n, double b){ KontenRecord ow = konten.get(n); // jetzt als typ if ( ow != null ) { ow.buche(b); konten.put(n,ow); } return ow.stand; } public double stand(int n) { KontenRecord ow = konten.get(n); if ( ow != null ) { return ow.stand; } else { return 0.0; } } // Prüfung, ob die Summe aller Stände 0.0 ist public boolean pruefe() { Collection<KontenRecord> werte = konten.values(); double summe = 0.0; for ( KontenRecord w : werte ) { // for statt Iterator summe += w.stand; } if ( Math.abs(summe) <= 1.0E-10 ) { // wegen Rundungsfehler kein summe == 0.0 return true; } else { return false; } } public String toString(int n) { String s = "<Konto "; s += "nr='" + n + "' >\n"; s += konten.get(n); // toString() s += "</Konto>"; return s; } public String toString() { String s = "\n<Konten geprueft='" + pruefe() + "' >\n"; // hole alle Schlüssel aus der Abbildung Set<Integer> nummern = konten.keySet(); //s += nummern + "\n"; // hole was für die Schleife // 1. einen Iterator Iterator<Integer> it = nummern.iterator(); // 2. hole Schlüssel mit next() while ( it.hasNext() ) { Integer i = it.next(); s += toString(i) + "\n"; } s += "</Konten>\n"; return s; } public void neuesKonto(int i, KontenRecord m) { if ( konten.get(i) != null ) { throw new IllegalArgumentException("Konto gibt es schon"); } konten.put(i,m); } public void textSpeichern(String dateiName) throws IOException { PrintWriter pw = new PrintWriter(dateiName); pw.println( toString() ); pw.close(); } public void speichern(String dateiName) throws IOException { ObjectAusgabe ow = new ObjectAusgabe(dateiName); ow.writeObject( konten ); ow.close(); } public void laden(String dateiName) throws IOException, ClassNotFoundException { ObjectEinlesen or = new ObjectEinlesen(dateiName); Map<Integer,KontenRecord> k = (Map<Integer, KontenRecord>) or.readObject(); or.close(); konten = k; } }
Beispiel:
import java.io.IOException; public class KontenObjectTest { public static void main(String[] args) { KontenMitRecord bank = new KontenMitRecord(); String datei = "eineBankDatei.stream"; if ( args.length > 0 ) { datei = args[0]; } try { bank.laden(datei); } catch (IOException e) { System.out.println("Fehler: " + e); //return; // Aufgabe: Wie geht das beim ersten mal? } catch (ClassNotFoundException e) { System.out.println("Fehler: " + e); return; } System.out.println("bank(anfang) = " + bank); if ( bank.size() == 0 ) { // initialisiere KontenRecord maier = new KontenRecord( "Ingo Maier", 0.0, 1, 0.0, "keine" ); KontenRecord king = new KontenRecord( "Helmut King", 0.0, 1, 0.0, "keine" ); bank.neuesKonto(17,maier); bank.neuesKonto(4711,king); } bank.buchen(17, 20.0); bank.buchen(4711,-20.0); System.out.println("bank(ende) = " + bank); try { bank.speichern( datei ); } catch(IOException e) { System.out.println("Fehler " + e); // normal hier nicht enden lassen sondern // neuer Versuch // Aufgabe: mit while-Schleife und Nachfrage } } }
Es folgen einige weitere Ideen für Programmier-Aufgaben und Projekte.
Ürarbeiten Sie die Methode main()
der
Klasse KontenObjectTest
:
Wenn beim ersten Aufruf des Programms die Datei noch leer ist, sollen die Konten geeignet initialisiert werden.
Wenn das Speichern in der Ausgabe-Datei ein Fehler auftritt, soll die Benutzerin solange gefragt werden was zu tun ist, bis das Problem behoben wurde.
Entwickeln Sie eine Methode textLaden(String dateiName)
der
Klasse KontenMitRecord
, so dass die Ausgabe der Methode
textSpeichern(String dateiName)
wieder eingelesen werden kann.
Bemerkung: Kann einige Tage zur Bearbeitung dauern.
Lernen Sie das Java API for XML Processing (JAXP) und verwenden Sie es
bei der Implementierung von textLaden()
.
Bemerkung: Kann einige Tage zur Bearbeitung dauern.
Entwickeln Sie eine grafische Benutzeroberfläche für die Klasse KontenMitRecord
.
In einer Maske sollen die notwendigen Informationen für den Konstuktor
der Klasse KontenRecord
erfasst werden und eine Kontonummer vergeben werden.
Zum Speichern und Laden können die vorhandenen Methoden als Aktion an einen Button
oder Menuepunkt gebunden werden.
Beispiel: Verzeichnis von Kontonummern und Kontendatensätzen in einer TreeMap.
import java.io.IOException; import java.io.PrintWriter; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.TreeMap; /** * Verzeichnis von Kontonummern und Kontendatensätzen. * * @author usr336b */ public class KontenMitRecord { // keys = integer, values = double // festlegung: keys haben typ Integer // values haben typ KontenRecord private Map<Integer,KontenRecord> konten; /** * Dieser Konstruktor initialisiert das Verzeichnis. */ public KontenMitRecord() { //konten = new HashMap<Integer,KontenRecord>(); konten = new TreeMap<Integer,KontenRecord>(); } /** * Die Anzahl der vorhandenen Konten. * @return die Anzahl der Konten. */ public int size() { return konten.size(); } /** * Methode zur Ausführung einer Buchung. * @param n die Kontonummer. * @param b der zu addierende Betrag. * @return den neuen Kontostand. */ public double buchen(int n, double b){ KontenRecord ow = konten.get(n); // jetzt als typ if ( ow != null ) { ow.buche(b); konten.put(n,ow); } return ow.stand; } /** * Methode zum Anzeigen den Kontostandes. * @param n die Kontonummer. * @return Kontestand für Konto Nummer n. */ public double stand(int n) { KontenRecord ow = konten.get(n); if ( ow != null ) { return ow.stand; } else { return 0.0; } } /** * Prüfung der doppelten Buchführung. * Test ob die Summe aller Kontostände 0.0 ist. * @return true falls die Prüfung erfolgreich ist, * sonst false. */ public boolean pruefe() { Collection<KontenRecord> werte = konten.values(); double summe = 0.0; for ( KontenRecord w : werte ) { // for statt Iterator summe += w.stand; } if ( Math.abs(summe) <= 1.0E-10 ) { // wegen Rundungsfehler kein summe == 0.0 return true; } else { return false; } } /** * Verwandle ein Konto in eine XML-Zeichenkette. * Hier kommt die Beschreibung der Datenstruktur... * <pre> * <Konto nr="n" > * ... * </Konto> * </pre> * @param n die Kontonummer. * @return Zeichenkette mit XML Datensatz. */ public String toString(int n) { String s = "<Konto "; s += "nr='" + n + "' >\n"; s += konten.get(n); // toString() s += "</Konto>"; return s; } /** * Verwandle alle Konten in eine XML-Zeichenkette. * @return Zeichenkette mit XML-Darstellung aller Konten. */ public String toString() { String s = "\n<Konten geprueft='" + pruefe() + "' >\n"; // hole alle Schlüssel aus der Abbildung Set<Integer> nummern = konten.keySet(); //s += nummern + "\n"; // hole was für die Schleife // 1. einen Iterator Iterator<Integer> it = nummern.iterator(); // 2. hole Schlüssel mit next() while ( it.hasNext() ) { Integer i = it.next(); s += toString(i) + "\n"; } s += "</Konten>\n"; return s; } /** * Lege ein neues Konto an. * @param i die Kontonummer. * @param m der Kontendatensatz. */ public void neuesKonto(int i, KontenRecord m) { if ( konten.get(i) != null ) { throw new IllegalArgumentException("Konto gibt es schon"); } konten.put(i,m); } /** * Speichere den Inhalt des Verzeichnisses * in einer Text-Datei. * @param dateiName der Name der Datei. * @throws IOException falls etwas schief geht. */ public void textSpeichern(String dateiName) throws IOException { PrintWriter pw = new PrintWriter(dateiName); pw.println( toString() ); pw.close(); } /** * Speichere den Inhalt des Verzeichnisses * in einer Serialisierten Object-Datei. * @param dateiName der Name der Datei. * @throws IOException falls etwas schief geht. */ public void speichern(String dateiName) throws IOException { ObjectAusgabe ow = new ObjectAusgabe(dateiName); ow.writeObject( konten ); ow.close(); } /** * Lade ein Verzeichnis aus einer Serialisierten * Object-Datei. * <b>Achtung:</b> der alte Inhalt wird überschrieben. * @param dateiName der Name der Datei. * @throws IOException falls etwas schief geht. * @throws ClassNotFoundException falls eine Klasse * nicht gefunden wird. */ public void laden(String dateiName) throws IOException, ClassNotFoundException { ObjectEinlesen or = new ObjectEinlesen(dateiName); Map<Integer,KontenRecord> k = (Map<Integer, KontenRecord>) or.readObject(); or.close(); konten = k; } }
Beispiel: Kontenverzeichnis mit vollständigerem Konto-Datensatz.
import java.io.Serializable; import java.util.Date; /** * Datensatz für ein Konto. * Hier werden alle interessanten Felder für * ein Konto definiert. * @author usr336b */ public class KontenRecord implements Serializable { String inhaber; double ueberziehungsKredit; Date datum; double stand; int konditionen; String bemerkungen; /** * Kontruktor für den Kontendatensatz. * @param inhaber der Eigentümer des Kontos. * @param kredit der Kreditrahmen für das Konto. * @param kond weitere Konditionen. * @param stand der aktuelle Kontostand. * @param bem weitere Bemerkungen. */ public KontenRecord( String inhaber, double kredit, int kond, double stand, String bem ) { this.inhaber = inhaber; this.ueberziehungsKredit = kredit; this.konditionen = kond; this.stand = stand; this.bemerkungen = bem; this.datum = new Date(); } /** * Buchen eines Betrages auf den Kontendatensatz. * @param b dieser Betrag wird auf den aktuellen * Kontostand addiert. */ public void buche(double b) { stand += b; } /** * Wandle den Datensatz in eine Zeichenkette um. * @return die Zeichenkette. */ public String toString() { String s = "<Record>\n"; s += "<Inhaber>" + inhaber + "</Inhaber>\n"; s += "<Stand>" + stand + "</Stand>\n"; // Aufgabe: die restlichen Info angeben s += "</Record>\n"; return s; } }
Beispiel:
import java.io.ObjectOutputStream; import java.io.FileOutputStream; import java.io.IOException; /** * Hilfsklasse für ObjectOutputStream in eine Datei. * @author usr336b */ public class ObjectAusgabe extends ObjectOutputStream { /** * Kontruktor zur Angabe eines Dateinamens. * @param name der Name einer Datei. * @throws IOException falls was schief geht. */ public ObjectAusgabe(String name) throws IOException { super( new FileOutputStream(name) ); } }
Beispiel:
import java.io.ObjectInputStream; import java.io.FileInputStream; import java.io.IOException; /** * Hilfsklasse für ObjectInputStream aus einer Datei. * @author usr336b */ public class ObjectEinlesen extends ObjectInputStream { /** * Konstruktor mit Angabe des Dateinamens. * @param dateiName der Name der Datei. * @throws IOException falls was schief geht. */ public ObjectEinlesen(String dateiName) throws IOException { super( new FileInputStream(dateiName) ); } }
Beispiel:
import java.io.IOException; /** * Eine Klasse zum Testen der Konten Anwendung. * Die <code>main()</code> Methode erzeugt eine bank * und führt einige Testbuchungen durch. * @author usr336b */ public class KontenObjectTest { /** * Die wichtige <code>main()</code> Methode wird * von der Laufzeitumgebung aufgerufen. * @param args ein Array von Kommandozeilen Parametern. */ public static void main(String[] args) { KontenMitRecord bank = new KontenMitRecord(); String datei = "eineBankDatei.stream"; if ( args.length > 0 ) { datei = args[0]; } try { bank.laden(datei); } catch (IOException e) { System.out.println("Fehler: " + e); //return; // Aufgabe: Wie geht das beim ersten mal? } catch (ClassNotFoundException e) { System.out.println("Fehler: " + e); return; } System.out.println("bank(anfang) = " + bank); if ( bank.size() == 0 ) { // initialisiere KontenRecord maier = new KontenRecord( "Ingo Maier", 0.0, 1, 0.0, "keine" ); KontenRecord king = new KontenRecord( "Helmut King", 0.0, 1, 0.0, "keine" ); bank.neuesKonto(17,maier); bank.neuesKonto(4711,king); } bank.buchen(17, 20.0); bank.buchen(4711,-20.0); System.out.println("bank(ende) = " + bank); try { bank.speichern( datei ); } catch(IOException e) { System.out.println("Fehler " + e); // normal hier nicht enden lassen sondern // neuer Versuch // Aufgabe: mit while-Schleife und Nachfrage } } }
Ergebnis von Javadoc
Es folgen einige weitere Ideen für Programmier-Aufgaben und Projekte.
Vervollständigen Sie die Javadoc-Kommentare bei den restlichen Klassen.
Beispiel: Thread Erzeugung und Nutzung am Beispiel von Rennautos als Threads
import java.util.List; public class RennAuto extends Thread { String auto; String fahrer; List<RennAuto> platz; /** * Ein Auto-Thread wird mit * einem Fahrer und Auto initialisiert. * @param p Liste für den Zieleinlauf * @param a das Auto * @param f der Fahrer oder die Fahrerin */ public RennAuto(List<RennAuto> p, String a, String f) { auto = a; fahrer = f; platz = p; } public String toString() { return fahrer + " mit " + auto; } /** * In dieser Methode passiert die Abarbeitung */ public void run() { System.out.println(this + " gestartet"); // das Rennen fahren rennenFahren(500); motorSchaden(); rennenFahren(500); synchronized (platz) { System.out.println(this.toString() + " im Ziel angekommen"); platz.add(this); } } void motorSchaden() { double w = Math.random(); // 0 <= w <= 1.0 if ( w > 0.5 ) { throw new RuntimeException("Motor von " + auto + " ist kaputt"); } } void rennenFahren(int max){ // Math.random() liefert double zwischen 0.0 und 1.0 try { sleep( (int)(max*Math.random()) ); } catch (InterruptedException e) { System.out.println("Dies sollte nicht passieren "+e); } } } //Thread.currentThread().sleep( (int)(max*Math.random()) );
Beispiel:
import java.util.ArrayList; import java.util.List; public class FormelEins { public static void main(String[] args) { List<RennAuto> platz = new ArrayList<RennAuto>(); // Erzeugen, starten und stoppen von RennAutos Thread t1 = new RennAuto(platz,"Ferrari","Schuhmacher"); Thread t2 = new RennAuto(platz,"RedBull","Vettel"); Thread t3 = new RennAuto(platz,"McLarrenMercedes","Hamilton"); System.out.println("Autos sind bereit"); t1.start(); t2.start(); t3.start(); System.out.println("Rennen gestartet"); try { t1.join(); t2.join(); t3.join(); } catch(InterruptedException e) { System.out.println("Fehler: " + e); } System.out.println("Rennen beendet"); System.out.println("Platzierung " + platz); //System.exit(0); } }
Es folgen einige weitere Ideen für Programmier-Aufgaben und Projekte.
Verwenden Sie ein elementares Array oder eine ArrayList
für die Speicherung der erzeugten Threads.
Starten Sie alle Threads in einer Schleife über die Array-Elemente und
warten Sie ebenso auf die Terminierung aller Threads in einer Schleife.
Erweitern Sie den Konstruktor von RennAuto
um einen Parameter für
die Höchstgeschwindigkeit und für die Ausfallwahrscheinlichkeit des Motors.
Berechnen Sie das Argument für die Methode rennenFahren()
nach der Formel "1000 - Höchstgeschwindigkeit".
Erweitern Sie die Parameterliste von motorSchaden()
um einen double
Wert, also zu motorSchaden(double pm)
.
Verwenden Sie diesen Wert Anstelle des festen Wertes 0.5
.
Führen Sie eine Text-Datei für die Teilnehmer eines Rennens ein. In der Datei soll der Name des Fahrers und das Auto mit weiteren Eigenschaften abgelegt sein. Die Werte sollen durch Komma getrennt werden. Zum Beispiel
# Fahrer, Auto, Höchstgeschwindigkeit, Motorschaden Wahrscheinlichkeit, ... Vettel, Red Bull, 230, 0.2, ... Hamilton, McLarenMercedes, 220, 0.3, ... Schuhmacher, Ferrari, 220, 0.2, ... ...
Lesen Sie zu Programmbeginn diese Datei ein und generieren Sie aus den Infos
in jeder Zeile eine RennAuto
Klasse.
Beispiel: sequentielle und parallele Matrizen-Multiplikation
public class SeqMult { public void multiply(double[][] C, double[][] A, double[][] B) { for (int i=0; i < A.length; i++) { for (int j=0; j < B[0].length; j++) { double c = 0.0; for (int k=0; k < B.length; k++) { c += A[i][k] * B[k][j]; } C[i][j] = c; } } } }
Beispiel:
import java.util.ArrayList; import java.util.List; public class ParMult { public void multiply(double[][] C, double[][] A, double[][] B) { List<Thread> threads = new ArrayList<Thread>(); for (int i=0; i < A.length; i++) { Thread t = new ZeilenMult(C,A,B,i); t.start(); threads.add(t); } for (Thread t : threads) { try { t.join(); } catch(Exception e) { System.out.println("Exception: " +e); } } } } class ZeilenMult extends Thread { double[][] A; double[][] B; double[][] C; int i; ZeilenMult(double[][] C, double[][] A, double[][] B, int i) { this.C = C; this.A = A; this.B = B; this.i = i; } public void run() { for (int j=0; j < B[0].length; j++) { double c = 0.0; for (int k=0; k < B.length; k++) { c += A[i][k] * B[k][j]; } C[i][j] = c; } } }
Beispiel:
import java.util.ArrayList; import java.util.List; public class ParProcMult { int anzahl; ParProcMult(int anzahl) { this.anzahl = anzahl; } public void multiply(double[][] C, double[][] A, double[][] B) { List<Thread> threads = new ArrayList<Thread>(); for (int i=0; i < anzahl; i++) { Thread t = new ZeilenMultProc(C,A,B,i,anzahl); t.start(); threads.add(t); } for (Thread t : threads) { try { t.join(); } catch(Exception e) { System.out.println("Exception: " +e); } } } } class ZeilenMultProc extends Thread { double[][] A; double[][] B; double[][] C; int ii; int anzahl; ZeilenMultProc(double[][] C, double[][] A, double[][] B, int i, int anzahl) { this.C = C; this.A = A; this.B = B; this.ii = i; this.anzahl = anzahl; } public void run() { int todo = A.length/anzahl; for ( int i = todo*ii; i < todo*(ii+1) ; i++) { for (int j=0; j < B[0].length; j++) { double c = 0.0; for (int k=0; k < B.length; k++) { c += A[i][k] * B[k][j]; } C[i][j] = c; } } } }
Beispiel:
public class MatMult { public static double[][] randomMat(int n){ double[][] mat = new double[n][n]; for ( int i = 0; i < n; i++ ) { for ( int j = 0; j < n; j++ ) { mat[i][j] = Math.random(); } } return mat; } public static double[][] zeroMat(int n){ double[][] mat = new double[n][n]; for ( int i = 0; i < n; i++ ) { for ( int j = 0; j < n; j++ ) { mat[i][j] = 0.0; } } return mat; } public static double[][] oneMat(int n){ double[][] mat = new double[n][n]; for ( int i = 0; i < n; i++ ) { for ( int j = 0; j < n; j++ ) { if ( i == j ) { mat[i][j] = 1.0; } else { mat[i][j] = 0.0; } } } return mat; } public static void printMat(double[][] mat){ for ( int i = 0; i < mat.length; i++ ) { for ( int j = 0; j < mat[0].length; j++ ) { System.out.print(mat[i][j]); if ( j < mat[0].length-1 ) { System.out.print(", "); } } System.out.println(); } System.out.println(); } public static boolean equalMat(double[][] A, double[][] B ){ double eps = Double.MIN_VALUE*10.0; for ( int i = 0; i < A.length; i++ ) { for ( int j = 0; j < A[0].length; j++ ) { double b = Math.abs(A[i][j]-B[i][j]); if ( b >= eps) { return false; } } } return true; } public static void main(String[] args) { int n = 1000; double[][] C = zeroMat(n); double[][] A = randomMat(n); double[][] B = randomMat(n); double[][] Cp = zeroMat(n); double[][] Cpp = zeroMat(n); SeqMult sm = new SeqMult(); ParMult pm = new ParMult(); ParProcMult pmp = new ParProcMult(100); System.out.println("Matrix A = "); //printMat(A); System.out.println("Matrix B = "); //printMat(B); long sstart = System.currentTimeMillis(); sm.multiply(C,A,B); long sstop = System.currentTimeMillis(); long pstart = System.currentTimeMillis(); pm.multiply(Cp,A,B); long pstop = System.currentTimeMillis(); System.out.println("Matrix C = "); long ppstart = System.currentTimeMillis(); pmp.multiply(Cpp,A,B); long ppstop = System.currentTimeMillis(); System.out.println("Matrix C = "); //printMat(C); System.out.println("seq Zeit = " + (sstop-sstart)); System.out.println("par Zeit = " + (pstop-pstart)); System.out.println("par proc Zeit = " + (ppstop-ppstart)); System.out.println("gleich = " + equalMat(Cp,C)); System.out.println("gleich = " + equalMat(Cpp,C)); //System.out.println("eps = " + Double.MIN_VALUE); System.out.println("Anzahl CPUs = " + Runtime.getRuntime().availableProcessors()); } }
Es folgen einige weitere Ideen für Programmier-Aufgaben und Projekte.
Messen Sie die Performance dieser Implementierungen für verschiedene Matrixgrößen, für verschiedene Thread-Anzahlen und verschiedenen Rechnern mit einer und mehreren CPUs.
Implementieren Sie ein Matrix-Benchmark Programm, mit dem Sie die
Performance verschiedener Matrix Multiplikationsalgorithmen vergleichen können
(analog zur Klasse MatMult
).
Vergleichen Sie die Algorithmen (der Methode multiply()
) der folgenden
Klassen:
SeqMult
ParMult
ParMultProc
, bzw. ParProcMult
SeqMultBlock
ParMultProcBlock
SeqMultTrans
SeqMultBlockTrans
ParMultProcTrans
ParMultProcBlockTrans
Die Klassen finden Sie hier.
Erfassen Sie die wichtigsten Daten des Benchmark Rechners: CPU Typ, Anzahl CPUs, Geschwindigkeit, Caches (evtl. L1,L2,L3), Hauptspeicher, Java Version. Erstellen Sie eine Tabelle etwa wie folgt:
Algorithmus | Matrixgrösse | Blockgrösse | Thread Anzahl | Rechenzeit in Sec |
... | ... | ... | ... | ... |
Bemerkung: Kann einige Tage zur Bearbeitung dauern.
Überlegen Sie wie Sie die Performance der Matrix-Multiplikation weiter verbessern können.
Beispiel: ein Konto, das sich parallel von mehreren Thredas aus benutzen lässt.
public class KontoSync { double stand; public KontoSync(double s) { this.stand = s; } public /*synchronized*/ void buchen(double b) { // mach was synchronized (this) { double a = stand; updateOtherThings(1000); a += b; stand = a; } // noch was } public double stand() { return stand; } public String toString(){ return "" + stand(); } void updateOtherThings(int max){ // Math.random() liefert double zwischen 0.0 und 1.0 try { Thread.currentThread().sleep( (int)(max*Math.random()) ); } catch (InterruptedException e) { System.out.println("Dies sollte nicht passieren "+e); } } }
Beispiel:
public class UeberweisungSync extends Thread { KontoSync a; KontoSync b; double betrag; public UeberweisungSync(KontoSync a, KontoSync b, double bb) { this.a = a; this.b = b; betrag = bb; } public void run () { a.buchen(-betrag); b.buchen(betrag); } }
Beispiel:
public class FinanzSync { public static void main(String[] args) { KontoSync a = new KontoSync(120); KontoSync b = new KontoSync(80); System.out.println("start a = " + a); System.out.println("start b = " + b); Thread[] threads = new Thread[6]; threads[0] = new UeberweisungSync(a,b,20); threads[1] = new UeberweisungSync(b,a,20); threads[2] = new UeberweisungSync(a,b,30); threads[3] = new UeberweisungSync(b,a,30); threads[4] = new UeberweisungSync(a,b,50); threads[5] = new UeberweisungSync(b,a,50); for ( int i = 0; i < 6; i++ ) { threads[i].start(); } System.out.println("mitte a = " + a); System.out.println("mitte b = " + b); for ( int i = 0; i < 6; i++ ) { try { threads[i].join(); } catch(InterruptedException e) { System.out.println("e = " + e); } } System.out.println("ende a = " + a); System.out.println("ende b = " + b); } }
Beispiel: ein Konto, das nicht ins Minus geht, sondern wartet bis Geld eingegengen ist.
public class KontoPlus { // diese Konto Klasse bleibt immer im plus. // d.h. der Kontostand ist >= 0. double stand; // Object m = new Object(); // funktioniert public KontoPlus(double s) { if ( s < 0 ) { throw new IllegalArgumentException(); } this.stand = s; } public /*synchronized*/ void buchen(double b) { // mach was synchronized (this) { double a = stand + b; updateOtherThings(1000); Thread t = Thread.currentThread(); while ( /*a < 0 */ -b > stand ) { // kein if !!!!! System.out.println("warte auf Geld " + t); try { this.wait(); // blockiert unbedingt } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("warten beendet " + t); a = stand + b; } if ( a >= 0 || a > stand ) { System.out.println("sende notify " + t); this.notifyAll(); // } stand = a; } // noch was } public double stand() { return stand; } public String toString(){ return "" + stand(); } void updateOtherThings(int max){ // Math.random() liefert double zwischen 0.0 und 1.0 try { Thread.currentThread().sleep( (int)(max*Math.random()) ); } catch (InterruptedException e) { System.out.println("Dies sollte nicht passieren "+e); } } }
Beispiel:
public class UeberweisungPlus extends Thread { KontoPlus a; KontoPlus b; double betrag; public UeberweisungPlus(KontoPlus a, KontoPlus b, double bb) { this.a = a; this.b = b; betrag = bb; } public void run () { a.buchen(-betrag); b.buchen(betrag); } }
Beispiel:
public class FinanzPlus { public static void main(String[] args) { KontoPlus a = new KontoPlus(20); KontoPlus b = new KontoPlus(80); System.out.println("start a = " + a); System.out.println("start b = " + b); Thread[] threads = new Thread[6]; threads[0] = new UeberweisungPlus(a,b,20); threads[1] = new UeberweisungPlus(b,a,20); threads[2] = new UeberweisungPlus(a,b,30); threads[3] = new UeberweisungPlus(b,a,30); threads[4] = new UeberweisungPlus(a,b,50); threads[5] = new UeberweisungPlus(b,a,20); // deadlock bei 20, 50 ist ok for ( int i = 0; i < 6; i++ ) { threads[i].start(); } System.out.println("mitte a = " + a); System.out.println("mitte b = " + b); for ( int i = 0; i < 6; i++ ) { try { threads[i].join(); } catch(InterruptedException e) { System.out.println("e = " + e); } } System.out.println("ende a = " + a); System.out.println("ende b = " + b); } }
Beispiele: mit BlockingQueue
aus java.util.concurrent
import java.util.List; public class DVD { List<Double> liste; // Spieldauer der songs String name; // Bezeichnung der DVD public DVD(String name, List<Double> liste) { this.name = name; this.liste = liste; } public String toString() { String s = "DVD(" + name; for ( Double d : liste ) { s += ", " + d; } return s + ")"; } public Double dauer() { double sum = 0.0; for ( Double d : liste ) { sum += d; } return sum; } }
Beispiel:
import java.util.ArrayList; import java.util.List; import java.util.concurrent.BlockingQueue; public class DVDGenerator extends Thread { int anzahl; BlockingQueue<DVD> stapel; public DVDGenerator(BlockingQueue<DVD> stapel, int anzahl) { this.stapel = stapel; this.anzahl = anzahl; } public void run() { for ( int i = 0; i < anzahl; i++ ) { List<Double> zeiten = new ArrayList<Double>(); int stueck = (int) (Math.random()*100); for ( int j = 0; j < stueck; j++ ) { double zeit = 1.0 + Math.random()*3.0; zeit = ((int)(zeit*100.0)/100.0); zeiten.add( zeit ); } DVD abba = new DVD("abba-"+i,zeiten); try { stapel.put(abba); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("abba = " + abba); } } }
Beispiel:
import java.util.concurrent.BlockingQueue; public class DVDSummator extends Thread { int anzahl; BlockingQueue<DVD> stapel; public DVDSummator(BlockingQueue<DVD> stapel, int anzahl) { this.stapel = stapel; this.anzahl = anzahl; } public void run() { double dauer = 0.0; for ( int i = 0; i < anzahl; i++ ) { try { DVD abba = stapel.take(); dauer += abba.dauer(); } catch (InterruptedException e) { System.out.println("e = " + e); } } System.out.println("dauer = " + dauer); } }
Beispiel:
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; public class DVDMain { public static void main(String[] args) { BlockingQueue<DVD> stapel = new ArrayBlockingQueue<DVD>(10); Thread gen = new DVDGenerator(stapel,20); gen.start(); Thread sum1 = new DVDSummator(stapel,10); Thread sum2 = new DVDSummator(stapel,10); sum1.start(); sum2.start(); try { gen.join(); sum1.join(); sum2.join(); } catch (InterruptedException e) { System.out.println("e = " + e); } } }
Beispiel: neue Version mit Summation der Teil-Ergebnisse.
import java.util.concurrent.BlockingQueue; public class DVDSummator extends Thread { int anzahl; BlockingQueue<DVD> stapel; double dauer = 0.0; public DVDSummator(BlockingQueue<DVD> stapel, int anzahl) { this.stapel = stapel; this.anzahl = anzahl; } public void run() { for ( int i = 0; i < anzahl; i++ ) { try { DVD abba = stapel.take(); dauer += abba.dauer(); } catch (InterruptedException e) { System.out.println("e = " + e); } } System.out.println("teil dauer = " + dauer); } }
Beispiel:
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; public class DVDMain { public static void main(String[] args) { BlockingQueue<DVD> stapel = new ArrayBlockingQueue<DVD>(10); Thread gen = new DVDGenerator(stapel,3000); gen.start(); Double dauer = 0.0; DVDSummator sum1 = new DVDSummator(stapel,1000); DVDSummator sum2 = new DVDSummator(stapel,1000); DVDSummator sum3 = new DVDSummator(stapel,1000); sum1.start(); sum2.start(); sum3.start(); try { gen.join(); sum1.join(); sum2.join(); sum3.join(); } catch (InterruptedException e) { System.out.println("e = " + e); } dauer += sum1.dauer; dauer += sum2.dauer; dauer += sum3.dauer; System.out.println("gesammte dauer = " + dauer); } }
Ändern Sie das Verfahren, wie die Teil-Ergebnisse aufsummiert werden:
Verlegen Sie die Summation in einen synchronized Bereich in jedem
DVDSummator
Thread.
Definieren Sie dazu eine Container Klasse mit einer synchronisierten
addTo()
methode.
Verwenden Sie eine synchonisierte Datenstruktur wie etwa
ArrayBlockingQueue
, um die Teilergebnisse in den Threads
zu speichern und diese dann im Hauptprogramm zusammen zu addieren.
Beispiel: Netzwerk Programmierung mit einem einfachen Client-Server Programm.
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import java.net.UnknownHostException; public class SimpleClient { public static void main(String[] args) { try { Socket s = new Socket("141.72.5.100",1337); System.out.println("connected to " + s); BufferedReader br = new BufferedReader( new InputStreamReader( s.getInputStream() ) ); String zeile = br.readLine(); System.out.println("Antwort vom Server " + zeile); PrintWriter pw = new PrintWriter(s.getOutputStream()); pw.println("Hallo lieber Server"); pw.close(); br.close(); s.close(); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
Beispiel: einfacher Server
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class SimpleServer { public static void main(String[] args) { try { ServerSocket se = new ServerSocket(1337); System.out.println("Server started = " + se); while ( true ) { System.out.println("waiting ..."); Socket s = se.accept(); System.out.println("connection from " + s); PrintWriter pw = new PrintWriter(s.getOutputStream()); pw.println("Hallo lieber Client"); BufferedReader br = new BufferedReader( new InputStreamReader( s.getInputStream() ) ); String zeile = br.readLine(); System.out.println("Antwort vom Client " + zeile); br.close(); pw.close(); s.close(); } //se.close(); } catch (IOException e) { e.printStackTrace(); } } }
Beispiel: einfacher Server, funktionierende Version
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class SimpleServer { public static void main(String[] args) { try { ServerSocket se = new ServerSocket(1337); System.out.println("Server started = " + se); while ( true ) { System.out.println("waiting ..."); Socket s = se.accept(); System.out.println("connection from " + s); PrintWriter pw = new PrintWriter(s.getOutputStream()); BufferedReader br = new BufferedReader( new InputStreamReader( s.getInputStream() ) ); pw.println("Hallo lieber Client"); pw.flush(); System.out.println("calling server readline ..."); String zeile = br.readLine(); System.out.println("Antwort vom Client " + zeile); br.close(); pw.close(); s.close(); } //se.close(); } catch (IOException e) { e.printStackTrace(); } } }
Beispiel: einfacher Client, funktionierende Version
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import java.net.UnknownHostException; public class SimpleClient { public static void main(String[] args) { try { Socket s = new Socket("141.72.5.100",1337); System.out.println("connected to " + s); PrintWriter pw = new PrintWriter(s.getOutputStream()); BufferedReader br = new BufferedReader( new InputStreamReader( s.getInputStream() ) ); System.out.println("calling client readline ..."); String zeile = br.readLine(); System.out.println("Antwort vom Server " + zeile); pw.println("Hallo lieber Server"); pw.flush(); pw.close(); br.close(); s.close(); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
Beispiel: einfacher Web-Server
import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class WebServer { public static void main(String[] args) { try { ServerSocket se = new ServerSocket(8080); System.out.println("Server started = " + se); while ( true ) { System.out.println("waiting ..."); Socket s = se.accept(); System.out.println("connection from " + s); PrintWriter pw = new PrintWriter(s.getOutputStream()); BufferedReader br = new BufferedReader( new InputStreamReader( s.getInputStream() ) ); // http Protokoll: GET /path/file.ext System.out.println("calling server readline ..."); String zeile = br.readLine(); System.out.println("Antwort vom Client " + zeile); //br.close(); dies war ein fehler if ( zeile.startsWith("GET ") ) { String name = zeile.substring(4); int i = name.indexOf(" "); name = name.substring(1,i); System.out.println("name = " + name); BufferedReader datei = new BufferedReader( new FileReader(name)); System.out.println("datei = " + datei); while (true) { String line = datei.readLine(); System.out.println("gelesen: " + line); if ( line == null ) { break; } pw.println("loaclhost: " + line); pw.flush(); } pw.flush(); } else { pw.println("invalid method"); pw.flush(); } pw.close(); s.close(); } //se.close(); } catch (IOException e) { e.printStackTrace(); } } }
Beispiel: einfacher Web Client
import java.io.BufferedReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import java.net.UnknownHostException; public class WebClient { public static void main(String[] args) { try { //Socket s = new Socket("www.dhbw-mannheim.de",80); Socket s = new Socket("localhost",8080); System.out.println("connected to " + s); PrintWriter pw = new PrintWriter(s.getOutputStream()); BufferedReader br = new BufferedReader( new InputStreamReader( s.getInputStream() ) ); // http version 0.9: pw.println("GET /index.html HTTP/1.0"); //pw.println("GET /piwik/piwik.php"); //pw.println("GET /typo3temp/stylesheet_ef2d27d571.css"); pw.flush(); PrintWriter datei = new PrintWriter( new FileWriter("geholt.html")); System.out.println("calling client readline ..."); while ( true ) { String zeile = br.readLine(); System.out.println("empfangen: " + zeile); if ( zeile == null ) { break; } //if ( ! zeile.contains("src") ) { // img/link src, a href, form action // continue; //} datei.println(zeile); datei.flush(); } datei.close(); System.out.println("done"); pw.close(); br.close(); s.close(); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
Es folgen einige weitere Ideen für Programmier-Aufgaben und Projekte.
Entwickeln Sie einen Web Client, der URLs aus den HTML Elementen
src
, href
oder action
extrahiert und in eine Datei schreibt.
Verbessern Sie den Web Server, so dass dieser sicher gegen Hacking durch Directory Traversal wird. Führen Sie dazu ein sogennantes Document-Root Verzeichnis ein, und limitieren Sie die Zugriffe auf Dateien in diesem Verzeichnis.
Beispiel: Sockets, die auch Objekte transportieren können.
import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.Socket; public class ObjectSocket { Socket s; ObjectOutputStream os; ObjectInputStream is; public ObjectSocket(Socket s) throws IOException { this.s = s; os = new ObjectOutputStream( s.getOutputStream() ); is = new ObjectInputStream( s.getInputStream() ); } public void send(Object o) throws IOException { os.writeObject(o); // besser synchronized(os) os.flush(); } public Object receive() throws IOException, ClassNotFoundException { return is.readObject(); // besser synchronized(is) } public void close() throws IOException { os.close(); is.close(); s.close(); } }
Beispiel: Ein Server, der beliebige Runnable Klassen ausführen kann.
import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class ExecServer { public static void main(String[] args) throws IOException, ClassNotFoundException { ServerSocket se = new ServerSocket(1337); while (true) { System.out.println("waiting for connection..."); Socket s = se.accept(); System.out.println("connection from " + s); ObjectSocket os = new ObjectSocket(s); Runnable r = (Runnable)os.receive(); r.run(); // rechnen os.send(r); os.close(); } } }
Beispiel: Interface für multipy() Methode.
public interface MMInf { public void multiply(double[][] C, double[][] A, double[][] B); }
Beispiel: Verteilte Matrix-Multiplikation (noch nicht fertig).
import java.io.IOException; import java.net.Socket; import java.net.UnknownHostException; public class DistMult /*implements MMInf*/ { int anzahl; String[] partners; public DistMult(String[] partners) { // host-names this.partners = partners; anzahl = partners.length; } public void multiply(double[][] C, double[][] A, double[][] B) throws UnknownHostException, IOException, ClassNotFoundException { RunMatrix[] proc = new RunMatrix[anzahl]; ObjectSocket[] link = new ObjectSocket[anzahl]; for ( int i = 0; i < anzahl; i++ ) { proc[i] = new RunMatrix(C,A,B,anzahl,i); link[i] = new ObjectSocket( new Socket(partners[i],1337) ); link[i].send( proc[i] ); } for ( int i = 0; i < anzahl; i++ ) { RunMatrix rm = (RunMatrix)link[i].receive(); int m = rm.i; proc[m] = rm; } // Matrix C zusammenfassen // Das Programm ist hier nicht fertig! } } //wird übers Netz verschickt und in ExecServer ausgeführt: class RunMatrix implements Runnable { double[][] C, A, B; int anzahl; int i; public RunMatrix(double[][] C, double[][] A, double[][] B, int anzahl, int i) { this.C = C; // später optimieren, damit nicht soviel this.A = A; // Daten übers Netz versendet werden this.B = B; this.anzahl = anzahl; this.i = i; } public void run() { // aus RowMultProc int schritte = A.length / anzahl; if ( A.length % schritte != 0 ) { schritte++; } for ( int ii = i*schritte; ii < Math.min((i+1)*schritte,A.length); ii++ ) { for ( int j = 0; j < B[0].length; j++ ) { double c = 0.0; for (int k = 0; k < B.length; k++ ) { c += A[ii][k] * B[k][j]; } C[ii][j] = c; } } } }
Beispiel: Verwendung von DistMult
.
Vorsicht: funktioniert nur für einen Partner!
DistMult
muss für mehrere Partner noch angepasst werden.
import java.io.IOException; import java.net.UnknownHostException; public class MatMultDist { public static double[][] randomMat(int n){ double[][] mat = new double[n][n]; for ( int i = 0; i < n; i++ ) { for ( int j = 0; j < n; j++ ) { mat[i][j] = Math.random(); } } return mat; } public static double[][] zeroMat(int n){ double[][] mat = new double[n][n]; for ( int i = 0; i < n; i++ ) { for ( int j = 0; j < n; j++ ) { mat[i][j] = 0.0; } } return mat; } public static double[][] oneMat(int n){ double[][] mat = new double[n][n]; for ( int i = 0; i < n; i++ ) { for ( int j = 0; j < n; j++ ) { if ( i == j ) { mat[i][j] = 1.0; } else { mat[i][j] = 0.0; } } } return mat; } public static void printMat(double[][] mat){ for ( int i = 0; i < mat.length; i++ ) { for ( int j = 0; j < mat[0].length; j++ ) { System.out.print(mat[i][j]); if ( j < mat[0].length-1 ) { System.out.print(", "); } } System.out.println(); } System.out.println(); } public static boolean equalMat(double[][] A, double[][] B ){ double eps = Double.MIN_VALUE*10.0; for ( int i = 0; i < A.length; i++ ) { for ( int j = 0; j < A[0].length; j++ ) { double b = Math.abs(A[i][j]-B[i][j]); if ( b >= eps) { return false; } } } return true; } public static void main(String[] args) { int n = 1000; double[][] C = zeroMat(n); double[][] A = randomMat(n); double[][] B = randomMat(n); double[][] Cp = zeroMat(n); double[][] Cpp = zeroMat(n); //SeqMult sm = new SeqMult(); //ParMult pm = new ParMult(); //ParProcMult pmp = new ParProcMult(100); String[] partner = new String[] { "localhost" }; // new String[1]; partner[0] = "localhost"; DistMult dm = new DistMult(partner); // funktioniert noch nicht für mehrere Partner! System.out.println("Matrix A = "); //printMat(A); System.out.println("Matrix B = "); //printMat(B); long sstart = System.currentTimeMillis(); //sm.multiply(C,A,B); long sstop = System.currentTimeMillis(); long pstart = System.currentTimeMillis(); try { dm.multiply(Cp,A,B); } catch(UnknownHostException e) { e.printStackTrace(); } catch(IOException e) { e.printStackTrace(); } catch(ClassNotFoundException e) { e.printStackTrace(); } long pstop = System.currentTimeMillis(); System.out.println("Matrix C = "); long ppstart = System.currentTimeMillis(); //pmp.multiply(Cpp,A,B); long ppstop = System.currentTimeMillis(); System.out.println("Matrix C = "); //printMat(C); System.out.println("seq Zeit = " + (sstop-sstart)); System.out.println("par Zeit = " + (pstop-pstart)); System.out.println("par proc Zeit = " + (ppstop-ppstart)); System.out.println("gleich = " + equalMat(Cp,C)); System.out.println("gleich = " + equalMat(Cpp,C)); //System.out.println("eps = " + Double.MIN_VALUE); System.out.println("Anzahl CPUs = " + Runtime.getRuntime().availableProcessors()); } }
Es folgen einige weitere Ideen für Programmier-Aufgaben und Projekte.
Fügen Sie die Klasse DistMult
zu dem Matrix-Benchmark Programm hinzu
und bringen Sie es zum Laufen.
Vergleichen Sie die Performance dieser Klasse mit der Performance
der sequentiellen und parallelen Implementierungen der Multiplikationsalgorithmen.
Vervollständigen Sie das Programm, so dass es mindestens für 2 Partner funktioniert.
Die Bonus-Aufgaben müssen bis zum Samstag, dem 18. Juli 2009 bei
mir per Email abgegeben sein, damit sie für die Klausur gezählt werden.
kredel [at] rz.uni-mannheim.de
Alle Programme und sonstige Dateien (wie die HTML-Datei) müssen in einem
ZIP-Archiv als Anhang in der Email enthalten sein.
Für die vollständige und richtige Bearbeitung der Bonus-Aufgaben
erhalten Sie 23 Punkte .