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.9 Mit dem Thread verbundene Variablen * Unterschiedliche Threads können ohne Probleme das gleiche Runnable ausführen, was auch ein übliches Szenario ist, wenn der Programmcode immer der gleiche ist. Doch auch wenn der Programmcode immer gleich bleibt, soll jedem Thread doch vielleicht ein eigener Speicherbereich zugeteilt werden, in dem er Informationen ablegen kann. Falls das Runnable-Objekt selbst eine Objektvariable hätte und pro Thread auf diese Weise ein neues Runnable-Objekt gebildet würde, wäre das kein Problem, doch müsste bei genau einem Runnable-Objekt und beliebig vielen Threads ein anderer Ort gefunden werden. ### 2.9.1 ThreadLocal Die Lösung ist relativ einfach: Es müsste eine Datenstruktur geben, die jeden laufenden Thread mit einem Objekt oder einer Datenstruktur assoziiert. Diese Struktur muss dann aus dem Runnable-Objekt heraus referenzierbar sein. Java bietet mit der Klasse java.lang.ThreadLocal eine Implementierung für thread-lokale Variablen (engl. thread-local storage [TLS]) an. Abbildung 2.12: UML-Diagramm von ThreadLocal
    class java.lang.ThreadLocal<T>
ThreadLocal() Erzeugt eine neue thread-lokale Variable. void set(T value) Setzt den Wert für den lokalen Thread. T get() Liefert den Wert, der mit dem aktuellen Thread verbunden ist. protected T initialValue() Die Methode kann überschrieben werden und liefert dann den Anfangswert beim ersten Aufruf von get() ohne vorangehendes set(). Der Standard ist null. void remove() Entfernt den Wert der thread-lokalen Variablen, um etwa Speicher freizumachen. Ein anschließendes get() liefert wieder den Wert aus initialValue(). #### Zählen mit thread-lokalen Variablen Das folgende Beispiel soll ein Runnable definieren, das endlos zählt. Der Clou ist aber, dass der Zähler keine lokale Variable, sondern eine thread-lokale Variable ist, die ThreadLocal verwaltet. Drei Threads sollen das gleiche Runnable abarbeiten: zwei neue Threads und der aktuell ausführende main-Thread: Listing 2.41: com/tutego/insel/thread/ThreadLocalDemo.java
    package com.tutego.insel.thread;

    public class ThreadLocalDemo
    {
      public static void main( String[] args )
      {
        Runnable runnable = new SimpleRunnable();
        new Thread( runnable ).start();
        new Thread( runnable ).start();
        runnable.run();
      }
    }

    class SimpleRunnable implements Runnable
    {
      private static final ThreadLocal<Integer> mem =
                               new ThreadLocal<Integer>()
      {
        @Override protected Integer initialValue() { return 1; }
      };

      @Override public void run()
      {
        while ( true )
        {
          System.out.println( Thread.currentThread().getName() +
                              ", " + mem.get() );
          mem.set( mem.get() + 1 );
        }
      }
    }
Den Startwert legt die überschriebene Methode initialValue() mit 1 fest. Da ThreadLocal einen Zähler speichert, ist der Datencontainer mit Integer typisiert. Die Ausgabe kann beginnen mit:
    main, 1
    main, 2
    main, 3
    main, 4
    main, 5
    Thread-0, 1
    Thread-1, 1
    Thread-0, 2
    Thread-1, 2
    Thread-0, 3
    Thread-1, 3
Entwicklungsumgebungen
Die IDE IntelliJ bietet die komfortable Möglichkeit, statische referenzierte nicht thread-sichere Objekte in ThreadLocal-Objekte zu konvertieren. Informationen dazu gibt es unter http://blogs.jetbrains.com/idea/2009/10/threadlocal-in-one-click/.
#### remove() nutzen Jeder Thread speichert einen Assoziativspeicher mit allen thread-lokalen Variablen. Damit im ThreadLocal vergessene Werte nicht zum Problem werden, sollten sie mit remove() wieder entfernt werden. Sonst entstehen langlebige Objektreferenzen, die zu einem Speicherleck führen können. Denn in heutigen Umgebungen werden Threads nicht einfach so gestartet und beendet, sondern leben fast schon ewig in einem Thread-Pool und werden immer wieder recycelt. Der Tipp, der sich daraus ableitet, ist der folgende: Wenn thread-lokale Variablen nicht mehr benötigt werden, sollten sie entfernt werden, denn werden sie es nicht, verstopfen sie den Speicher. Das Problem ist nur, dass ein Thread im Thread-Pool ja gar nicht weiß, was für ein Runnable er abarbeitet, sodass es schwierig ist, Einträge wieder zu entfernen.[13](Sun hat das viele Jahre auch nicht vorgesehen. ThreadLocal gibt es seit Java 1.2, aber remove() erst seit Java 5.) ### 2.9.2 InheritableThreadLocal Jeder Thread kann einen neuen Thread bilden, der dann Kind ist. Da die statische main-Methode selbst von einem Haupt-Thread ausgeführt wird, wie das Beispiel zeigt, ist schon dieser Thread der Vater, der neue Unter-Threads bildet. Mit der Klasse InheritableThreadLocal, die eine Unterklasse von ThreadLocal ist, kann das Kind vom Vater den gespeicherten Wert übernehmen. Das würde sonst nicht funktionieren, da der neue Thread ja ganz eigene Werte hat, aber mit InheritableThreadLocal bleibt dieser Wert erhalten und wird auf die Kinder vererbt. Dass ein gestarteter Kind-Thread den Wert vom Vater-Thread übernimmt, zeigt das folgende Programm. Ein Thread gibt den geerbten Wert aus und setzt anschließend einen neuen Wert für ein Kind, das der Thread in die Welt entlässt: Listing 2.42: com/tutego/insel/thread/InheritableThreadLocalDemo.java
    package com.tutego.insel.thread;

    public class InheritableThreadLocalDemo
    {
      public static void main( String[] args )
      {
        new InheritingThread().start();
      }
    }

    class InheritingThread extends Thread
    {
    //  private static final ThreadLocal<String> mem = new ThreadLocal<String>();
      private static final InheritableThreadLocal<String> mem =
                                  new InheritableThreadLocal<String>();

      @Override public void run()
      {
        System.out.println( Thread.currentThread() + " bekommt " + mem.get() );
        mem.set( Thread.currentThread().getName() );

        new InheritingThread().start();
      }
    }
Die Ausgabe beginnt mit:
    Thread[Thread-0,5,main] bekommt null
    Thread[Thread-1,5,main] bekommt Thread-0
    Thread[Thread-2,5,main] bekommt Thread-1
    Thread[Thread-3,5,main] bekommt Thread-2
Der erste Thread bekommt noch nichts von seinem Vater-Thread. Da jedoch der erste Thread den eigenen Namen in den Speicher von InheritableThreadLocal legt und dann der zweite neu gestartete Kind-Thread auf den Wert zugreift, empfängt er die Zeichenfolge »Thread-0«. Wer zum Testen InheritableThreadLocal durch ThreadLocal ersetzt, der wird merken, dass das Beispiel so nicht funktioniert. ### 2.9.3 ThreadLocalRandom als Zufallszahlengenerator Zufallszahlen sind immer nur Pseudozufallszahlen und werden mit einer mathematischen Formel aus dem Vorgänger generiert. Der Vorgänger muss dabei gespeichert werden, und das ist die Aufgabe eines Random-Objekts. Die Methode Math.random() nutzt intern ein Random-Objekt, und jetzt kann es zu Wartezeiten kommen, wenn mehrere Threads gleichzeitig random() aufrufen, denn die Methode darf intern ja nur einen Thread die letzte Zufallszahl schreiben lassen. Um Zufallszahlen schnell generieren zu können, sind diese Verzögerungen ungünstig, und es gibt zwei Lösungen dafür. Einmal lässt sich pro Thread ein Random-Objekt generieren, sodass es im Code der Random-Klasse dann keine Konkurrenzsituation geben kann. Aber optimal ist das noch nicht, denn der Programmcode der Random-Klasse ist auf diese Nebenläufigkeit vorbereitet, und besser wäre ein schlankerer Programmcode, der für eine single-threaded Abarbeitung optimiert ist. Und hier kommt die unter Java 7 eingeführte Klasse java.util.concurrent.ThreadLocalRandom ins Spiel. Sie ist eine Unterklasse von Random und überschreibt die nextXXX()-Methoden so, dass es keine Synchronisation gibt; der Code ist dementsprechend schnell. Um etwa Zufallszahlen zwischen 1 und 10 zu erzeugen, schreiben wir mit der neuen Klasse: Listing 2.43: com/tutego/insel/thread/ThreadLocalRandomDemo.java
    ThreadLocalRandom threadLocalRandom = ThreadLocalRandom.current();
    System.out.println( threadLocalRandom.nextInt( 1, 10 + 1 ) );
    System.out.println( threadLocalRandom.nextInt( 1, 10 + 1 ) );
### 2.9.4 ThreadLocal bei der Performance-Optimierung ThreadLocal ist eine schöne Klasse zur Performance-Optimierung. Sollen zum Beispiel zwei Threads große Datenmengen über einen zentralen Puffer lesen, müssten sie an diesem Puffer synchronisiert werden. Mit ThreadLocal kann je ein Puffer beim Thread gespeichert sein, und die Synchronisation kann entfallen. Da es im Allgemeinen wenige Threads gibt, ist die Anzahl paralleler Puffer klein. Performance-Interessierte können einen Blick auf StringCoding werfen, wie sie ThreadLocal beim Caching von (De)Kodierer-Objekten nutzt. Die Klasse String nutzt StringCoding bei der Byte/Zeichen-Kodierung. Verschweigen dürfen wir aber nicht, dass der Zugriff auch etwas kostet, sodass ein kleiner synchronisierter Bereich durchaus schneller sein kann. Dazu noch ein Punkt zum Caching: Wir hatten gesagt, dass sich gecachte Objekte sehr gut in einem ThreadLocal ablegen lassen, insbesondere dann, wenn diese Objekte teuer im Aufbau sind. Hier müssen wir aber vorsichtig sein. Ein Szenario: Ein Server nutzt 100 Threads für Anfragen. Es kommt eine Anfrage herein, ein Thread übernimmt sie und setzt ein zu cachendes Objekt in den ThreadLocal. Das Dumme ist, dass die nächste Anfrage aber nicht wieder bei diesem Thread landen muss, denn es gibt ja 99 andere Threads, und die haben den gecachten Wert nicht im ThreadLocal. Also machen die das Gleiche, und es endet nach einer Zeit damit, dass alle 100 Threads dieses Objekt in einem lokalen Cache haben. Diese Herangehensweise kostet viel Speicher, kann aber intelligent sein, da so eine Synchronisation unnötig wird. Ist Speicher satt vorhanden und sind die Objekte klein und nicht thread-sicher, ist das eine gute Philosophie, ansonsten ist vielleicht doch eine zentrale Stelle für die Objekte eine speicherschonendere Strategie. ### 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