[Java] Architektur mit Threads

Dieses Thema im Forum "Programmierung & Entwicklung" wurde erstellt von Mr.y, 28. Juni 2012 .

  1. 28. Juni 2012
    Architektur mit Threads

    Hallo, ich möchte zwischen mehreren Threads unterscheiden können.
    Dabei möchte ich anhand des Thread-Namens was bestimmtes ausführen.
    Aber der folgende Code-Abschnitt will net laufen

    ich könnte Anhand der Variable "enumThreadName" in den jeweiligen Case springen.

    aber durch das befüllen:

    incompatibel.
    Wie mach das bei Java?

    Danke für jeden Tipp.
     
  2. 28. Juni 2012
    AW: EnumProblem

    Wenn du das Enum erst zur Laufzeit erstellen willst mit den Namen der Threads und dann mit SwitchCase weiter arbeiten willst, so müssen doch eh dank SwitchCase die Namen schon lange vorher bekannt sein, ansonsten könntest du ja nicht wirklich was bei SwitchCase zu ordnen, oder?

    Long story short: Du kannst Enums nicht zur Laufzeit füllen. Entweder du schreibst dir selbst eine Enum-Klasse oder siehe meinen Text oben^^
     
    1 Person gefällt das.
  3. 28. Juni 2012
    AW: EnumProblem

    danke für deine schnelle antwort,

    ja der name des treads wird ja ausgelesen.

    Aber ich möchte nicht schreiben

    Case "ersterTredd":


    case "zweiterTread"

    sondern eben enum dafür verwenden
    was mich auch irretiert, ist, dass sowohl Tread und Enum haben "toString()" Methoden, dennoch geht das net und ich kann nicht das eine dem anderen zu weisen, muss ich dafür echt ne klasse schreiben?
     
  4. 28. Juni 2012
    Zuletzt bearbeitet: 28. Juni 2012
    AW: EnumProblem

    Ich verstehe dein Problem nicht so richtig.

    Wie wäre es wenn du die Funktionalität, die ein Thread ausführen soll, in eine eigene Threadklasse auslagerst und anhand deiner konkreten Thread-Objekte mit Thread.isRunning() bzw. Thread.State herausfindest, welcher grade läuft und dann die entsprechende Methode des jeweiligen Threads aufrufst?

    Hier noch ein Link dazu: Galileo Computing :: Java ist auch eine Insel
     
    1 Person gefällt das.
  5. 28. Juni 2012
    Zuletzt bearbeitet: 28. Juni 2012
    AW: EnumProblem

    Es wäre natürlich am besten, wenn du genau vordefinierte Methoden hast, die du aufrufst, die aber immer nur was unterschiedliches tun.

    Das kannst du mit Interfaces oder mit abstrakten Klassen erreichen. Je nach Einsatzzweck eignet sich das eine mehr oder weniger.

    Ein Beispiel muss ich dir nach dem Spiel mal basteln, hatte bemerkt, dass meins irgendwie gerade den Sinn nicht wirklich gut und brauchbar vermittelt.
     
  6. 28. Juni 2012
    Zuletzt bearbeitet: 28. Juni 2012
    AW: EnumProblem

    Ich habe das jetzt 10x gelesen und bin mir immer noch nicht sicher was du erreichen willst. Wenn man davon ausgeht, dass du irgendwelche Aussagen über Threads zur Laufzeit machen möchtets ist das Wahrscheinlich der - naja - "speziellste" Ansatz den ich gesehen habe (ich kann nicht Ansatzweise nachvollziehen, wie man überhaupt auf so eine Idee kommt).

    Versuchs mal so:

    Code:
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    
    public class Threads {
     public static List<Thread> threadList = new ArrayList<>();
    
     public static void main(String[] args) {
    
     Thread myThread1 = new Thread(new Runnable() {
     @Override
     public void run() {
     for (int i = 0; i < 10; i++) {
     i++;
     System.out.println(Thread.currentThread().getName()
     + " Stand: " + i);
     }
     }
     }, "myThread1");
    
     Thread myThread2 = new Thread(new Runnable() {
     @Override
     public void run() {
     for (int i = 10; i < 100; i++) {
     i++;
     System.out.println(Thread.currentThread().getName()
     + " Stand: " + i);
     }
     }
     }, "myThread2");
    
     threadList.addAll(Arrays.asList(myThread1, myThread2));
    
     for (Thread thread : threadList) {
     thread.start();
     }
     }
    
    }
    
    Dazu kommt noch folgendes:

    • Auf eine Case folgt normalerweise ein break, keine Ahnung ob sich das mit Java7 geändert hat
    • Ich habe die Threads jetzt wegen der Lesbarkeit als Anonymous-Innerclasses eingebunden. Sollten die Threads komplexere Aufgaben erfüllen rate ich dazu:
      Code:
      public class mySpecialThread extends Thread { ... } 
      
      Du musst dann jedoch "run()" manuell überschreiben.
    • In Java solltest du Enumerations weitgehend als "statisches Element" betrachten. Klassen sind meistens der bessere Weg. Enumerations dienen fast ausschließlich zum Bündeln irgendwelcher Konstanten in Gruppen.
    • Du kannst im Stil der letzten for-Schleife immer über deine Threads iterieren und ggf. speziell behandeln.

      Code:
      for (Thread thread : threadList) {
       if(thread.getName().equals("evilThreadofDoom")) thread.stop();
      }
      
      (Wobei Thread.stop() nicht genutzt werden sollte - dient nur zur Lesbarkeit. Man sollte Threads über Bedingungen auslaufen lassen.)

    Keine Ahnung ob dir das irgendwie Hilft bzw. ich dein Problem verstanden habe. Ansonsten würde mir noch etwas mit Listenern bzw. Callbacks einfallen, dass dein Problem lösen könnte.
     
  7. 28. Juni 2012
    Zuletzt bearbeitet: 28. Juni 2012
    AW: EnumProblem

    danke sehr für deinen Vorschlag Alex².

    Also mein ursprünglicher Ansatz war der, irgendwie in der "Run"-Methode zwischen verschiedenen Threads zu unterscheiden.

    ich hab von dem Interface "runable" ja nur diese eine "run" Methode bekommen.
    Und wenn 2 oder mehrere Threads verschiedenes machen sollten, dann müsste man ja zwischen denen unterschieden können. Ich dachte mir, ich löse das am schnellsten über switch-case.


    @Calyx

    Alle Thread-Objekte laufen gleichzeitig und rufen die einzigste "Run" Methode auf.
    Irgendwie muss ja ein Konstrukt her, wo ich zwischen unterschiedlichen Threads untersteiden kann.


    Das mit den Thread in eigene Klassen zu stecken und sie dann über das Inteface anzusprechen, hört sich für mich gut an.

    Nur....kann man immer fest davon ausgehen, dass es nicht mehr als bsp. 10 Threads sprich 10 Klassen sind?

    Kann es passieren, dass ich nen 11-Thread starte, der dann keine passende Klasse hat?

    Bin neu in der Sache...
     
  8. 28. Juni 2012
    AW: EnumProblem

    Also das ist ja auch so ne Idee^^ Nein, du erstellst einfach für jede Aufgabe eine Thread-Klasse (kann natürlich auch anonym sein). Die Instanzen davon können ja unabhängig von einander laufen (Sinn von Threads...) und führen jeweils nur ihre run-Methode aus.
     
  9. 29. Juni 2012
    Zuletzt bearbeitet: 29. Juni 2012
    AW: EnumProblem

    Du kannst fuer jeden Thread eine eigene run-Methode schreiben und wieviele Threads du startest bleibt ja dir ueberlassen. Ueber die Variablen (hier thread1 und thread2) kannst du die Threads unterscheiden und in den run-Methoden kannst du das machen was du moechtest. So hat jede Art von Thread ihre eigene Klasse und laesst sich ueber das Objekt in Main starten, du koenntest natuerlich auch mehrere Threads der gleichen Klasse starten, musst dann halt nur noch ein Objekt davon erzeugen. Oder wie meinst du das mit 10 Threads/Klassen?

    Code:
    package com.toby.rr.threads;
    
    public class Main {
    
     public static void main(String... args) {
    
     FirstThread thread1 = new FirstThread();
     SecondThread thread2 = new SecondThread();
    
     try {
     System.out.println("Thread1-State: " + thread1.getState());
     System.out.println("Thread2-State: " + thread2.getState());
     thread1.start();
     thread2.start();
     System.out.println("Thread1-State: " + thread1.getState());
     System.out.println("Thread2-State: " + thread2.getState());
     Thread.sleep(5000);
     thread1.stop = true;
     thread2.stop = true;
     System.out.println("Thread1-State: " + thread1.getState());
     System.out.println("Thread2-State: " + thread2.getState());
     } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
     }
     }
    }
    
    Code:
    package com.toby.rr.threads;
    
    public class FirstThread extends Thread {
    
     volatile boolean stop = false;
     int i = 1;
    
     public void run() {
     while (!stop) {
     doSomething();
     }
     System.out.println("Thread1 stopped");
     }
    
     public void doSomething() {
     try {
     System.out.println("FirstThread: " + i++);
     Thread.sleep(400);
     } catch (InterruptedException e) {
     // NOP
     }
     }
    }
    
    Code:
    package com.toby.rr.threads;
    
    public class SecondThread extends Thread {
    
     volatile boolean stop = false;
     int i = 1;
    
     public void run() {
     while (!stop) {
     doSomething();
     }
     System.out.println("Thread2 stopped");
     }
    
     public void doSomething() {
     try {
     System.out.println("SecondThread: " + i++);
     Thread.sleep(400);
     } catch (InterruptedException e) {
     // NOP
     }
     }
    }
    
     
  10. 1. Juli 2012
    Zuletzt bearbeitet: 1. Juli 2012
    AW: EnumProblem

    ahso ok, also zusammengefasst, soll man für jeden Thread eine Klasse schreiben.
    Diese Klasse implementiert das "Runable"-Interface mit der Methode "run".
    Und in der Main, rufe ich dann einfach die jeweilige Klasse vom passenden Thread auf.

    Wenn ich bsp. ein LKW, Rennwagen, Cabrio habe, die "gleichzeitig" fahren, aber eben unterschiedlich.
    Dann habe ich für alle 3 Auto-Typen drei Thread Klassen, mit 1 Run-Methode je Klasse.

    Dann muss ich ja nur noch "beschleunigen", "fahren" und "bremsen" in jeweils ner Thread-Klasse schreiben (weil sie ja unterschiedlich fahren) und in der "run"-Methode aufrufen?
     
  11. 1. Juli 2012
    Zuletzt bearbeitet: 1. Juli 2012
    AW: EnumProblem

    Jup, genauso siehts aus.

    An deinem Beispiel mit den Autos könnte man noch Polymorphie ergänzen. Alle 3 sind Fahrzeuge die einige Gemeinsamkeiten haben, also könnte man eine (abstrakte) Oberklasse Fahrzeug bilden in der das zusammengefasst wird (4 Reifen, Auspuff, Rückspiegel, usw). Die einzelnen konkreten Autos erweitern dann die Oberklasse Fahrzeug (Rennwagen extends Fahrzeug) und implementieren ihre speziellen Sachen (Geschwindigkeit, Bremsverhalten, Anzahl Sitze, usw). Nur so als Tipp, das spart viel Arbeit

    Ob du Runnable implementierst oder Thread erweiterst ist egal. In Java gibt es keine Mehrfachvererbung, deshalb gibt es neben der Klasse Thread noch das Interface Runnable, welches im Prinzip nur die run-Methode vorschreibt. Wenn du also eine Situation hast, in der eine Unterklasse von einer anderen Klasse erbt und zusätzlich als Thread laufen soll, kannst du einfach Runnable implementieren statt Thread zu erweitern (Rennwagen extends Fahrzeug implements Runnable).
     
  12. 2. Juli 2012
    AW: EnumProblem

    ich musste jetzt mal den Treadnamen überschreiben.

    Also mit Polymorphie hab ich mir das durch den Kopf gehen lassen und finde das eher net so toll.

    Denn, wenn ich mit 2 Threads gleichzeitig die Methode beschleunigen aufrufe,
    dann werden beide erstmal den Code von der Superklasse ausführen und dann die Modifikation in der eigenen Klasse.
    Dann könnte das ganze ja ausgebremst werden, wenn beide auf die Methode einschlagen, deswegen will ich die drei Methoden getrennt halten.

    Deswegen tendiere ich eher für ein Interface. D.h. Ich implementiere 2 Interface´s "Runnable" und "AutoInterface" (mit drei Methoden)

    Weiss aber nun nicht genau, wie ich den Ablauf gestalten sollte, hat da jemand nen rat? oder Idee?

    Ich möchte einfach, dass ein LKW-Thread beispielsweise die getrennt-implementierte LKW.beschleunigen ausführt und dann, dass der LKW-Thread die getrennte LKW.bremsen ausführt.
    Also dass ein Thread unterschiedliche Funktionen ausführt.
    oder wie könnte man das anders gestalten? ausser Polymorphie^^
     
  13. 2. Juli 2012
    Zuletzt bearbeitet: 2. Juli 2012
    AW: Architektur mit Threads

    So und nicht anders würde es Sinn machen (vom Klassen-Konzept her) und ich rate dir erneut dich erst mal mit den Mechanismen zu befassen:

    Fahrzeug.java (Diese Klasse enthält alles, was die Fahrzeuge gemeinsam haben!!!)
    Code:
    public abstract class Fahrzeug implements Runnable {
    
     private String marke;
     private String name;
     private int maxGeschwindigkeit = 0;
     private int momentanGeschwindigkeit = 0;
    
     private boolean motorLäuft = false;
    
     @Override
     public void run() {
     while (true) {
     while (motorLäuft) {
     try {
     Thread.sleep(1000 - getMomentanGeschwindigkeit());
     } catch (InterruptedException e) {
     e.printStackTrace();
     }
     motorLoop();
     }
     try {
     Thread.sleep(1000);
     } catch (InterruptedException e) {
     e.printStackTrace();
     }
     }
    
     }
    
     protected abstract void motorLoop();
    
     public void motorStarten() {
     if (!motorLäuft) {
     System.out.println(getMarke() + " " + getName()
     + " Motor gestartet.");
     this.motorLäuft = true;
     }
    
     }
    
     public void motorStoppen() {
     if (motorLäuft) {
     this.motorLäuft = false;
     System.out.println(getMarke() + " " + getName()
     + " Motor gestoppt.");
     }
    
     }
    
     public String getName() {
     return name;
     }
    
     public void setName(String name) {
     this.name = name;
     }
    
     public int getMaxGeschwindigkeit() {
     return maxGeschwindigkeit;
     }
    
     public void setMaxGeschwindigkeit(int maxGeschwindigkeit) {
     this.maxGeschwindigkeit = maxGeschwindigkeit;
     }
    
     public String getMarke() {
     return marke;
     }
    
     public void setMarke(String marke) {
     this.marke = marke;
     }
    
     public int getMomentanGeschwindigkeit() {
     return momentanGeschwindigkeit;
     }
    
     public void setMomentanGeschwindigkeit(int momentanGeschwindigkeit) {
     this.momentanGeschwindigkeit = momentanGeschwindigkeit;
     }
    
    }
    
    LKW.java (So kannst du auch alle anderen Fahrzeuge implementieren!!! Hier kommen Fahrzeugspezifische Dinge hinzu.)
    Code:
    import java.util.Date;
    
    public class LKW extends Fahrzeug {
    
     private int achsen;
    
     public LKW() {
     setMarke("MAN");
     setName("TGX");
     setMaxGeschwindigkeit(100);
     this.achsen = 3;
     }
    
     @Override
     protected void motorLoop() {
     System.out.println((new Date()).toString() + getMarke() + " "
     + getName() + " mit " + getMomentanGeschwindigkeit()
     + "km/h auf " + getAchsen() + " Achsen in bewegung.");
     }
    
     public int getAchsen() {
     return achsen;
     }
    
     public void setAchsen(int achsen) {
     this.achsen = achsen;
     }
    
    }
    
    
    Main.java (Kleiner Test, macht mehr Spaß wenn du dir noch ein Fahrzeug implementierst!!!)
    Code:
    public class Main {
     public static void main(String[] args) {
     LKW lkw = new LKW();
     Thread lkwThread = new Thread(lkw);
     lkwThread.start();
    
     lkw.motorStarten();
     lkw.setMomentanGeschwindigkeit(20);
     }
    }
    
    Output:
    Code:
    MAN TGX Motor gestartet.
    Mon Jul 02 21:26:31 CEST 2012MAN TGX mit 20km/h auf 3 Achsen in bewegung.
    Mon Jul 02 21:26:32 CEST 2012MAN TGX mit 20km/h auf 3 Achsen in bewegung.
    Mon Jul 02 21:26:33 CEST 2012MAN TGX mit 20km/h auf 3 Achsen in bewegung.
    Mon Jul 02 21:26:34 CEST 2012MAN TGX mit 20km/h auf 3 Achsen in bewegung.
    Mon Jul 02 21:26:35 CEST 2012MAN TGX mit 20km/h auf 3 Achsen in bewegung.
    
    Wird, wie gesagt deutlicher, wenn du mehrere Fahrzeuge parallel laufen lässt. Die "beschleunigen()"-Methode würde man dann in "Fahrzeug" implementieren, sodass diese Auswirkung auf "maxGeschwindigkeit" hat.
     
    1 Person gefällt das.
  14. 2. Juli 2012
    AW: Architektur mit Threads

    Mir war grad langweilig, deswegen hab ich schnell was gemacht, auch wenn du es nicht mit Polymorphie haben möchtest^^

    Eine abstrakte Klasse ist sowas wie ein Interface, bietet aber mMn besondere Vorteile. Du kannst wie bei Interfaces von ihr keine Objekte erzeugen, du kannst Methoden deklarieren und die Signatur vorgeben, aber der Unterschied ist: du kannst schon fertige Methoden implementieren, die in allen erbenden Klassen vorhanden sein sollen, sowie Attribute definieren.

    Hier mal mein Beispiel:
    Spoiler
    Code:
    public [B]abstract[/B] class AbstractFahrzeug implements Runnable {
    
     private static final int REIFEN = 4;
     private static final int RÜCKSPIEGEL = 3;
     private static final boolean AUSPUFF = true;
    
     private boolean motorGestartet = false;
     private boolean fahrerSitzt = false;
     protected int geschwindigkeit = 0;
    
     protected void einsteigen() {
     fahrerSitzt = true;
     }
    
     protected void starteMotor() {
     motorGestartet = true;
     }
    
     protected void fahrbereitMachen() {
     einsteigen();
     starteMotor();
     }
    
     abstract void beschleunigen();
    
     abstract void bremsen();
    }
    
    Code:
    public class Cabrio extends AbstractFahrzeug {
    
     @Override
     void beschleunigen() {
     geschwindigkeit = 150;
     }
    
     @Override
     void bremsen() {
     geschwindigkeit = 0;
     }
    
     @Override
     public void run() {
     fahrbereitMachen();
     beschleunigen();
     System.out.println("Cabrio: Geschwindigkeit ist " + geschwindigkeit);
     }
    }
    Code:
    public class LKW extends AbstractFahrzeug {
    
     @Override
     void beschleunigen() {
     geschwindigkeit = 80;
     }
    
     @Override
     void bremsen() {
     geschwindigkeit = 0;
     }
    
     @Override
     public void run() {
     fahrbereitMachen();
     beschleunigen();
     System.out.println("LKW: Geschwindigkeit ist " + geschwindigkeit);
     }
    }
    
    Code:
    public class Rennwagen extends AbstractFahrzeug {
    
     @Override
     void beschleunigen() {
     geschwindigkeit = 250;
     }
    
     @Override
     void bremsen() {
     geschwindigkeit = 0;
     }
    
     @Override
     public void run() {
     einsteigen();
     beschleunigen();
     System.out.println("Rennwagen: Geschwindigkeit ist " + geschwindigkeit);
     }
    }
    
    Code:
    public class Main {
    
     public static void main(String[] args) {
     Cabrio cabrio = new Cabrio();
     LKW lkw = new LKW();
     Rennwagen rennwagen = new Rennwagen();
    
     new Thread(cabrio).start();
     new Thread(lkw).start();
     new Thread(rennwagen).start();
     }
    }
    

    In der abstrakten Klasse AbstractFahrzeug sind "Einsteigen" und "Motor starten" sowie "Fahrbereit machen" schon implementiert, weil das ja so gut wie bei jedem Fahrzeug das selbe ist. Zusätzlich sind ein paar Attribute definiert (4 Reifen, Auspuff, Rückspiegel), die auch alle gemeinsam haben. Auf die Methoden sowie Attribute in dieser Klasse können alle erbenden Klassen zugreifen.

    Da "Beschleunigen" und "Bremsen" als abstract deklariert sind, muss eine erbende Klasse diese Methoden genau wie bei einem Interface selbst implementieren. In zb Cabrio sind nur die run-Methode sowie das jeweils individuelle "Beschleunigen" und "Bremsen". So muss man keinen Code duplizieren und hat die Klassen schön sauber.

    Ein weiterer Vorteil ist, dass du Änderungen, die alle Klassen betreffen, nur an einer Stelle ändern musst. Wenn also alle Autos plötzlich ohne Auspuff gebaut werden, müsstest du nur in AbstractFahrzeug AUSPUFF = false setzen. Würde jede Klasse ein Interface implementieren, müsstest du das in jeder Klasse einzeln ändern, da in jeder Klasse ein eigener Auspuff deklariert ist.

    Sorry für die Wall of Text^^
     
  15. 2. Juli 2012
    Zuletzt bearbeitet: 2. Juli 2012
    AW: Architektur mit Threads

    so, habs mir angeschaut und da hab ich ne grundsätzliche Frage

    Bei euren "RUN"-Methoden wird ja immer das selbe ausgeführt.

    bei Calyx
    einsteigen();
    beschleunigen();

    und bei Alex²
    motorLoop();

    Aber was ist, wenn ich in dieser "Run"-Methode mal eine und mal die andere Thread-Tätigkeit ausführen möchte?
    Ich will darauf hinaus, dass ich praktisch nicht mehr entscheiden kann, was ich den nun in der Run-Methode ausführen möchte?

    Heisst das, dass ich für jede Funktionalität ne extra Klasse haben muss mit der eigenen Run-Methode?

    nehmen wir mal einen anderen Beispiel an, vielleicht wirds verständlicher, was ich meine^^

    Kunde A überweist geld:
    ich starte die Run-Methode von ThreadA, dieser ThreadA seiterseits ruft irgendwie, die Methode "überweisen"

    Kunde B zahlt geld ein:
    ich starte Run-Methode von ThreadA, dieser ThreadA (der selbe Thread wie von eben), der ruft nun aber die Methode "einzahlen" ein.

    Kunde C bucht geld ab:

    ich starte Run-Methode von ThreadA, dieser ThreadA ruft nun die dritte Methode auf, die dann seinerseits geld abbucht.

    Und diese 3 Tätigkeiten werden von einer und der selben Thread-Methode zur der selben Zeit ausgeführt:

    KundeA.einzahlen
    KundeB.überweisen
    KundeC.abbuchen
     
  16. 2. Juli 2012
    AW: Architektur mit Threads

    Hhhmm.....beide Vorschläge sind sehr interessant, werde sie mir in den nächsten stunden anschauen, danke noch mal
     
  17. 3. Juli 2012
    AW: Architektur mit Threads

    Ich glaube du hast noch nicht ganz verstanden wozu nebenläufige Programmierung gut ist.

    Du (A) gehst doch nicht zum Bankautomaten und überweist Geld, lässt die Karte stecken und B und C kommen dann an und zahlen mit deiner noch eingesteckten Karte was auf ihre eigenen Konten ein. Das sind doch völlig voneinander unabhängige Vorgänge.

    Für die Unterscheidung ob jetzt Einzahlen, Abheben oder Überweisen gemacht wird kannst du dem Thread beim Erstellen (zb in Main) über den Konstruktor Parameter übergeben und dann mit if-else oder switch gucken ob, welche, wieviele... Methode(n) in run ausgeführt werden sollen.

    Aber: Ein Thread = eine nebenläufige Aufgabe in einem Prozess. Mehr nebenläufige Aufgaben = mehr Threads.
     
  18. 3. Juli 2012
    Zuletzt bearbeitet: 3. Juli 2012
    AW: Architektur mit Threads

    Nein, hat er ganz und gar nicht. Und ich wette, dass er sich immer noch nicht die entsprechenden Informationen eingeholt hat. Wir können ihm jetzt auch noch 10-Mal zeigen wie das Modell gedacht ist und er wird immer wieder mit seiner falschen Denkweise argumentieren und irgendein abstrakt falsches Beispiel bringen. Er versucht sich immer wieder ein Beispiel zu schaffen indem er unsere Erklärungen bzw. logische (feste) Muster außer Kraft setzt.

    Galileo Computing :: Java ist auch eine Insel - 12 Einf

    LESEN, VERSTHEN
     
  19. Video Script

    Videos zum Themenbereich

    * gefundene Videos auf YouTube, anhand der Überschrift.