Galileo Computing < openbook >
Galileo Computing - Programming the Net
Galileo Computing - Programming the Net


Java ist auch eine Insel (2. Aufl.) von Christian Ullenboom
Programmieren für die Java 2-Plattform in der Version 1.4
Java ist auch eine Insel (2. Auflage)
gp Kapitel 9 Threads und nebenläufige Programmierung
  gp 9.1 Prozesse und Threads
  gp 9.2 Threads erzeugen
    gp 9.2.1 Threads über die Schnittstelle Runnable implementieren
    gp 9.2.2 Threads über Runnable starten
    gp 9.2.3 Die Klasse Thread erweitern
    gp 9.2.4 Erweitern von Thread oder implementieren von Runnable?
  gp 9.3 Threads schlafen
    gp 9.3.1 Eine Zeituhr
  gp 9.4 Die Klassen Timer und TimerTask
  gp 9.5 Die Zustände eines Threads
    gp 9.5.1 Das Ende eines Threads
    gp 9.5.2 Einen Thread höflich mit Interrupt beenden
    gp 9.5.3 Der stop() von außen
    gp 9.5.4 Das ThreadDeath-Objekt
    gp 9.5.5 Auf das Ende warten mit join()
  gp 9.6 Arbeit niederlegen und wieder aufnehmen
  gp 9.7 Priorität
    gp 9.7.1 Threads hoher Priorität und das AWT
    gp 9.7.2 Granularität und Vorrang
  gp 9.8 Dämonen (engl. Daemon)
  gp 9.9 Kooperative und nicht kooperative Threads
  gp 9.10 Synchronisation über kritische Abschnitte
    gp 9.10.1 Gemeinsam genutzte Daten
    gp 9.10.2 Probleme beim gemeinsamen Zugriff und kritische Abschnitte
    gp 9.10.3 Punkte parallel initialisieren
    gp 9.10.4 i++ sieht atomar aus, ist es aber nicht
    gp 9.10.5 Abschnitte mit synchronized schützen
    gp 9.10.6 Monitore
    gp 9.10.7 Synchronized-Methode am Beispiel der Klasse StringBuffer
    gp 9.10.8 Synchronisierte Blöcke
    gp 9.10.9 Vor- und Nachteile von synchronisierten Blöcken und Methoden
    gp 9.10.10 Nachträglich synchronisieren
    gp 9.10.11 Monitore sind reentrant, gut für die Geschwindigkeit
    gp 9.10.12 Deadlocks
  gp 9.11 Variablen mit volatile kennzeichnen
  gp 9.12 Synchronisation über Warten und Benachrichtigen
    gp 9.12.1 Warten mit wait() und Aufwecken mit notify()
    gp 9.12.2 Mehrere Wartende und notifyAll()
    gp 9.12.3 wait() mit einer Zeitspanne
    gp 9.12.4 Beispiel Erzeuger-Verbraucher-Programm
    gp 9.12.5 Semaphoren
  gp 9.13 Grenzen von Threads
  gp 9.14 Aktive Threads in der Umgebung
  gp 9.15 Gruppen von Threads in einer Thread-Gruppe
    gp 9.15.1 Etwas über die aktuelle Thread-Gruppe herausfinden
    gp 9.15.2 Threads in einer Thread-Gruppe anlegen
    gp 9.15.3 Methoden von Thread und ThreadGroup im Vergleich
  gp 9.16 Einen Abbruch der virtuellen Maschine erkennen


Galileo Computing

9.9 Kooperative und nicht kooperative Threads  toptop

Mit der Methode sleep() legen wir den aktuellen Thread für eine bestimmte Zeit auf Eis. Das ist für das darunter liegende Betriebssystem nur gut, denn wenn ein Thread die ganze Berechnungszeit für sich beansprucht, dann kann dies schon einmal zu Problemen führen. Dies hängt auch mit dem Betriebssystem und der Lastenverteilung zusammen. Die meisten modernen Betriebssysteme sind preemptiv (auch präemptiv), wenige noch kooperativ (Win 3.11, altes MacOS). Ein kooperatives Betriebssystem verlangt vom Programmierer, dass dieser seine ablaufenden Programme so gestaltet, dass sie freiwillig nach einer gewissen Zeit die Kontrolle über den Prozessor abgeben. Preemptive Betriebssysteme entziehen einem Programm die Kontrolle über den Prozessor gegebenenfalls zwangsweise. Unter Solaris und Windows kann sich die verzahnte Ausführung mehrerer Threads unterscheiden, da beide Betriebssysteme die Rechenzeit auf verschiedene Weise auf die Threads aufteilen. Frühe Windows-Programme zeigten das unangenehme Verhalten, dass sie ihre Rechenzeit nicht abgaben. Die Kooperation mit anderen Programmen beziehungsweise dem System war nicht mehr gegeben.

Beispiel   Die Konsequenzen kooperativen und nicht kooperativen Programmierens

Wir befinden uns in einer run()-Routine.
public void run()
{
  double d = 1;
  // Ein paar teure Operationen
  for ( int i = 1; i < 1000000; i++ )
    d = Math.cos(i*d) * Math.sin(i*d);
}

Die Zeilen in dieser Routine sind so kompakt, dass wir bei manchen Betriebssystemen das Phänomen beobachten, dass das ganze System steht.

Neben sleep() gibt es noch eine weitere Methode, um kooperative Threads zu programmieren; die Methode yield(). Sie funktioniert etwas anders als sleep(), denn sie fügt den Thread bezüglich seiner Priorität in die Thread-Warteschlange des Systems ein. Die Warteschlange nimmt die Threads immer entsprechend der Priorität heraus (Prioritätswarteschlange), und daher laufen einige Threads öfter und andere weniger oft. Die Priorität kann von 1 bis 10 eingestellt werden – normal ist 5. Wir hätten also im Beispiel mit dem Thread, der auf eine bestimmte Uhrzeit wartet, die Priorität ruhig auf 1 stellen können (mit der Funktion setPriority()). Ein Thread mit der Priorität N wird vor allen Threads mit der Wichtigkeit kleiner N, aber hinter denen der Priorität größer gleich N gesetzt. Ruft nun ein kooperativer Thread mit der Priorität N die Methode yield() auf, bekommt ein Thread mit der Priorität <= N auch eine Chance zur Ausführung.

class java.lang.Thread
implements Runnable

gp  void yield()
Der laufende Thread wird kurz angehalten und lässt andere Threads auch zum Zuge kommen. Das ist die Idee der Methode, aber sie ist nicht verbindlich.
gp  void setPriority( int newPriority )
Ändert die Priorität des Threads (nachdem wiederum checkAccess() uns freie Bahn gibt). Befindet sich die Priorität nicht zwischen MIN_PRIORITY (1) oder MAX_PRIORITY (10), kommt es zu einer IllegalArgumentException.




Copyright © Galileo Press GmbH 2003
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> 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 GmbH, Gartenstraße 24, 53229 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de