Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Vorwort
1 Neues in Java 7
2 Threads und nebenläufige Programmierung
3 Datenstrukturen und Algorithmen
4 Raum und Zeit
5 Dateien, Verzeichnisse und Dateizugriffe
6 Datenströme
7 Die eXtensible Markup Language (XML)
8 Dateiformate
9 Grafische Oberflächen mit Swing
10 Grafikprogrammierung
11 Netzwerkprogrammierung
12 Verteilte Programmierung mit RMI
13 RESTful und SOAP Web-Services
14 JavaServer Pages und Servlets
15 Applets
16 Datenbankmanagement mit JDBC
17 Technologien für die Infrastruktur
18 Reflection und Annotationen
19 Dynamische Übersetzung und Skriptsprachen
20 Logging und Monitoring
21 Java Native Interface (JNI)
22 Sicherheitskonzepte
23 Dienstprogramme für die Java-Umgebung
Stichwort
Download: - openbook, ca. 21,3 MB
Buch bestellen
Ihre Meinung?
<< zurück | Galileo Computing / <openbook> / Java 7 - Mehr als eine Insel | vor >>
Java 7 - Mehr als eine Insel von Christian Ullenboom Das Handbuch zu den Java SE-Bibliotheken
Java 7 - Mehr als eine Insel Galileo Computing 1433 S., 2012, geb. 49,90 Euro, ISBN 978-3-8362-1507-7 |
| 2 Threads und nebenläufige Programmierung
|  | 2.1 Threads erzeugen
|  |  | 2.1.1 Threads über die Schnittstelle Runnable implementieren
|  |  | 2.1.2 Thread mit Runnable starten
|  |  | 2.1.3 Die Klasse Thread erweitern
|  | 2.2 Thread-Eigenschaften und -Zustände
|  |  | 2.2.1 Der Name eines Threads
|  |  | 2.2.2 Wer bin ich?
|  |  | 2.2.3 Die Zustände eines Threads *
|  |  | 2.2.4 Schläfer gesucht
|  |  | 2.2.5 Mit yield() auf Rechenzeit verzichten
|  |  | 2.2.6 Der Thread als Dämon
|  |  | 2.2.7 Das Ende eines Threads
|  |  | 2.2.8 Einen Thread höflich mit Interrupt beenden
|  |  | 2.2.9 UncaughtExceptionHandler für unbehandelte Ausnahmen
|  |  | 2.2.10 Der stop() von außen und die Rettung mit ThreadDeath *
|  |  | 2.2.11 Ein Rendezvous mit join() *
|  |  | 2.2.12 Arbeit niederlegen und wieder aufnehmen *
|  |  | 2.2.13 Priorität *
|  | 2.3 Der Ausführer (Executor) kommt
|  |  | 2.3.1 Die Schnittstelle Executor
|  |  | 2.3.2 Die Thread-Pools
|  |  | 2.3.3 Threads mit Rückgabe über Callable
|  |  | 2.3.4 Mehrere Callable abarbeiten
|  |  | 2.3.5 ScheduledExecutorService für wiederholende Ausgaben und Zeitsteuerungen nutzen
|  | 2.4 Synchronisation über kritische Abschnitte
|  |  | 2.4.1 Gemeinsam genutzte Daten
|  |  | 2.4.2 Probleme beim gemeinsamen Zugriff und kritische Abschnitte
|  |  | 2.4.3 Punkte parallel initialisieren
|  |  | 2.4.4 i++ sieht atomar aus, ist es aber nicht *
|  |  | 2.4.5 Kritische Abschnitte schützen
|  |  | 2.4.6 Kritische Abschnitte mit ReentrantLock schützen
|  |  | 2.4.7 Synchronisieren mit synchronized
|  |  | 2.4.8 Synchronized-Methoden der Klasse StringBuffer *
|  |  | 2.4.9 Mit synchronized synchronisierte Blöcke
|  |  | 2.4.10 Dann machen wir doch gleich alles synchronisiert!
|  |  | 2.4.11 Lock-Freigabe im Fall von Exceptions
|  |  | 2.4.12 Deadlocks
|  |  | 2.4.13 Mit synchronized nachträglich synchronisieren *
|  |  | 2.4.14 Monitore sind reentrant – gut für die Geschwindigkeit *
|  |  | 2.4.15 Synchronisierte Methodenaufrufe zusammenfassen *
|  | 2.5 Synchronisation über Warten und Benachrichtigen
|  |  | 2.5.1 Die Schnittstelle Condition
|  |  | 2.5.2 It’s Disco-Time *
|  |  | 2.5.3 Warten mit wait() und Aufwecken mit notify() *
|  |  | 2.5.4 Falls der Lock fehlt: IllegalMonitorStateException *
|  | 2.6 Datensynchronisation durch besondere Concurrency-Klassen *
|  |  | 2.6.1 Semaphor
|  |  | 2.6.2 Barrier und Austausch
|  |  | 2.6.3 Stop and go mit Exchanger
|  | 2.7 Atomare Operationen und frische Werte mit volatile *
|  |  | 2.7.1 Der Modifizierer volatile bei Objekt-/Klassenvariablen
|  |  | 2.7.2 Das Paket java.util.concurrent.atomic
|  | 2.8 Teile und herrsche mit Fork und Join *
|  |  | 2.8.1 Algorithmendesign per »teile und herrsche«
|  |  | 2.8.2 Paralleles Lösen von D&C-Algorithmen
|  |  | 2.8.3 Fork und Join
|  | 2.9 Mit dem Thread verbundene Variablen *
|  |  | 2.9.1 ThreadLocal
|  |  | 2.9.2 InheritableThreadLocal
|  |  | 2.9.3 ThreadLocalRandom als Zufallszahlengenerator
|  |  | 2.9.4 ThreadLocal bei der Performance-Optimierung
|  | 2.10 Threads in einer Thread-Gruppe *
|  |  | 2.10.1 Aktive Threads in der Umgebung
|  |  | 2.10.2 Etwas über die aktuelle Thread-Gruppe herausfinden
|  |  | 2.10.3 Threads in einer Thread-Gruppe anlegen
|  |  | 2.10.4 Methoden von Thread und ThreadGroup im Vergleich
|  | 2.11 Zeitgesteuerte Abläufe
|  |  | 2.11.1 Die Typen Timer und TimerTask
|  |  | 2.11.2 Job-Scheduler Quartz
|  | 2.12 Einen Abbruch der virtuellen Maschine erkennen
|  | 2.13 Zum Weiterlesen
# 2 Threads und nebenläufige Programmierung »Es ist nicht zu wenig Zeit, die wir haben, sondern es ist zu viel Zeit, die wir nicht nutzen.« – Lucius Annaeus Seneca (ca. 4 v. Chr.– 65 n. Chr.), römischer Philosoph und Staatsmann ## 2.1 Threads erzeugen Die folgenden Abschnitte verdeutlichen, wie der nebenläufige Programmcode in einen Runnable verpackt und dem Thread zur Ausführung vorgelegt wird. ### 2.1.1 Threads über die Schnittstelle Runnable implementieren Damit der Thread weiß, was er ausführen soll, müssen wir ihm Anweisungsfolgen geben. Diese werden in einem Befehlsobjekt vom Typ Runnable verpackt und dem Thread übergeben. Wird der Thread gestartet, arbeitet er die Programmzeilen aus dem Befehlsobjekt parallel zum restlichen Programmcode ab. Die Schnittstelle Runnable ist schmal und schreibt nur eine run()-Methode vor.
    interface java.lang.Runnable
void run() Implementierende Klassen realisieren die Operation und setzen dort den parallel auszuführenden Programmcode ein. Abbildung 2.1: UML-Diagramm der einfachen Schnittstelle Runnable Wir wollen zwei Threads angeben, wobei einer zwanzigmal das aktuelle Datum und die Uhrzeit ausgibt und der andere einfach eine Zahl: Listing 2.1: com/tutego/insel/thread/DateCommand.java
    package com.tutego.insel.thread;

    public class DateCommand implements Runnable
    {
      @Override public void run()
      {
        for ( int i = 0; i < 20; i++ )
          System.out.println( new java.util.Date() );
      }
    }
Listing 2.2: com/tutego/insel/thread/CounterCommand.java
    package com.tutego.insel.thread;

    class CounterCommand implements Runnable
    {
      @Override public void run()
      {
        for ( int i = 0; i < 20; i++ )
          System.out.println( i );
      }
    }
Unser parallel auszuführender Programmcode in run() besteht aus einer Schleife, die in einem Fall ein aktuelles Date-Objekt ausgibt und im anderen Fall einen Schleifenzähler. ### 2.1.2 Thread mit Runnable starten Nun reicht es nicht aus, einfach die run()-Methode einer Klasse direkt aufzurufen, denn dann wäre nichts nebenläufig, sondern wir würden einfach eine Methode sequenziell ausführen. Damit der Programmcode parallel zur Applikation läuft, müssen wir ein Thread-Objekt mit dem Runnable verbinden und dann den Thread explizit starten. Dazu übergeben wir dem Konstruktor der Klasse Thread eine Referenz auf das Runnable-Objekt und rufen start() auf. Nachdem start() für den Thread eine Ablaufumgebung geschaffen hat, ruft es intern selbstständig die Methode run() genau einmal auf. Läuft der Thread schon, so löst ein zweiter Aufruf der start()-Methode eine IllegalThreadStateException aus: Listing 2.3: com/tutego/insel/thread/FirstThread.java, main()
    Thread t1 = new Thread( new DateCommand() );
    t1.start();

    Thread t2 = new Thread( new CounterCommand() );
    t2.start();
Beim Starten des Programms erfolgt eine Ausgabe auf dem Bildschirm, die in etwa so aussehen kann:
    Tue Aug 21 16:59:58 CEST 2007
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Tue Aug 21 16:59:58 CEST 2007
    10
    ...
Deutlich ist die Verzahnung der beiden Threads zu erkennen. Was allerdings auf den ersten Blick etwas merkwürdig wirkt, ist die erste Zeile des Datum-Threads und viele weitere Zeilen des Zähl-Threads. Dies hat jedoch nichts zu bedeuten und zeigt deutlich den Nichtdeterminismus[4](Nicht vorhersehbar, bedeutet hier: Wann der Scheduler den Kontextwechsel vornimmt, ist unbekannt.) bei Threads. Interpretiert werden kann dies jedoch durch die unterschiedlichen Laufzeiten, die für die Datums- und Zeitausgabe nötig sind.
    class java.lang.Thread
    implements Runnable
Thread(Runnable target) Erzeugt einen neuen Thread mit einem Runnable, das den parallel auszuführenden Programmcode vorgibt. void start() Ein neuer Thread – neben dem die Methode aufrufenden Thread – wird gestartet. Der neue Thread führt die run()-Methode nebenläufig aus. Jeder Thread kann nur einmal gestartet werden.
Hinweis
Wenn ein Thread im Konstruktor einer Runnable-Implementierung gestartet wird, sollte die Arbeitsweise bei der Vererbung beachtet werden. Nehmen wir an, eine Klasse leitet von einer anderen Klasse ab, die im Konstruktor einen Thread startet. Bildet die Applikation ein Exemplar der Unterklasse, so werden bei der Bildung des Objekts immer erst die Konstruktoren der Oberklasse aufgerufen. Dies hat zur Folge, dass der Thread schon läuft, auch wenn das Objekt noch nicht ganz gebaut ist. Die Erzeugung ist erst abgeschlossen, wenn nach dem Aufruf der Konstruktoren der Oberklassen der eigene Konstruktor vollständig abgearbeitet wurde.
### 2.1.3 Die Klasse Thread erweitern Da die Klasse Thread selbst die Schnittstelle Runnable implementiert und die run()-Methode mit leerem Programmcode bereitstellt, können wir auch Thread erweitern, wenn wir eigene parallele Aktivitäten programmieren wollen: Listing 2.4: com/tutego/insel/thread/DateThread.java, DateThread
    public class DateThread extends Thread
    {
      @Override public void run()
      {
        for ( int i = 0; i < 20; i++ )
          System.out.println( new Date() );
      }
    }
Dann müssen wir kein Runnable-Exemplar mehr in den Konstruktor einfügen, denn wenn unsere Klasse eine Unterklasse von Thread ist, reicht ein Aufruf der geerbten Methode start(). Abbildung 2.2: UML-Diagramm der Klasse Thread, die Runnable implementiert Danach arbeitet das Programm direkt weiter, führt also kurze Zeit später die nächste Anweisung hinter start() aus: Listing 2.5: com/tutego/insel/thread/DateThreadUser, main()
    Thread t = new DateThread();
    t.start();
    new DateThread().start();      // (*)
Die (*)-Zeile zeigt, dass das Starten sehr kompakt auch ohne Zwischenspeicherung der Objektreferenz möglich ist.
    class java.lang.Thread
    implements Runnable
void run() Diese Methode in Thread hat einen leeren Rumpf. Unterklassen überschreiben run(), sodass sie den parallel auszuführenden Programmcode enthält. #### Überschreiben von start() und Selbststarter Die Methode start() kann von uns auch überschrieben werden, was aber nur selten sinnvoll beziehungsweise nötig ist. Wir müssen dann darauf achten, super.start() aufzurufen, damit der Thread wirklich startet. Damit wir als Thread-Benutzer nicht erst die start()-Methode aufrufen müssen, kann ein Thread sich auch selbst starten. Der Konstruktor ruft dazu einfach die eigene start()- Methode auf:
    class DateThread extends Thread
    {
      DateThread()
      {
        start();
      }
      // ...  der Rest bleibt ...
    }
#### run( ) wurde statt start( ) aufgerufen: Ja, wo laufen sie denn? Ein Programmierfehler, der Anfängern schnell unterläuft, ist folgender: Statt start() rufen sie aus Versehen run() auf dem Thread auf. Was geschieht? Fast genau das Gleiche wie bei start(), nur mit dem Unterschied, dass die Objektmethode run() nicht parallel zum übrigen Programm abgearbeitet wird. Der aktuelle Thread bearbeitet die run()-Methode sequenziell, bis sie zu Ende ist und die Anweisungen nach dem Aufruf an die Reihe kommen. Der Fehler fällt nicht immer direkt auf, denn die Aktionen in run() finden ja statt – nur eben nicht nebenläufig. #### Erweitern von Thread oder Implementieren von Runnable? Die beste Idee wäre, Runnable-Objekte zu bauen, die dann dem Thread übergeben werden. Befehlsobjekte dieser Art sind recht flexibel, da die einfachen Runnable-Objekte leicht übergeben und sogar von Threads aus einem Thread-Pool ausgeführt werden können. Ein Nachteil der Thread-Erweiterung ist, dass die Einfachvererbung störend sein kann; erbt eine Klasse von Thread, ist die Erweiterung schon »aufgebraucht«. Doch, egal ob eine Klasse Runnable implementiert oder Thread erweitert, eines bleibt: eine neue Klasse. ### Ihr Kommentar Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen. >> Zum Feedback-Formular
<< zurück | <top> | vor >>
Zum Katalog
Java 7 – Mehr als eine Insel Jetzt bestellen
Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen? Ihre Meinung
Buchempfehlungen
| Java und XML
| Einstieg in Eclipse 3.7
| Android 3
| NetBeans Platform 7
| Java ist auch eine Insel
| Apps entwickeln für Android 4
| Java 7
Shopping
Versandkostenfrei bestellen in Deutschland und Österreich Info

Copyright © Galileo Press 2012
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

[Galileo Computing]
Galileo Press, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de