Übung 1.4: Thread-Engpass auflösen

Bevor Sie mit dieser Übung beginnen, sollten Sie Übung 1.3: Thread-Engpass feststellen ausgeführt haben.

Für die Suche nach der gegenseitigen Sperre in Ihrem Code können Sie neben der Thread-Ansicht das UML2-Folgediagramm (Ansichten "Objektinteraktionen" und "Thread-Interaktionen") sowie die Profilerstellungsressource "Aufruf-Stack" im Monitor für Profilerstellung verwenden.

Um diese gegenseitige Sperre aufzulösen, wollen wir zunächst herausfinden, welche Methodenaufrufe und Objekte zu diesem Problem beitragen:

  1. Suchen Sie in der Thread-Ansicht den ersten Thread philo*, der in den Status "Wartet auf Sperre" eintritt. Bewegen Sie den Cursor auf das Segment "Wartet auf Sperre". Die Kurzinfo gibt die Sperre an, auf die der Thread wartet: Fork.<ID-Nummer>.
  2. Klicken Sie mit der rechten Maustaste auf die Profilerstellungsressource für den Durchgang und wählen Sie Öffnen mit > UML2-Objektinteraktionen aus. Daraufhin wird die Ansicht "UML2-Folgediagramm" mit den Objektinteraktionen geöffnet.
  3. Blättern Sie im Folgediagramm zur Sperre Fork.<ID-Nummer> vor und klicken Sie doppelt auf die Sperre, um sie auszuwählen.
  4. Blättern Sie die Anzeige vor und suchen Sie nach einem waagerechten Pfeil von einem der philo*-Threads zu Fork.<ID-Nummer>. Diese Pfeile zeigen die Interaktionen zwischen Objekten an. Die erste Interaktion zwischen diesen beiden Objekten gibt an, dass der philo*-Thread Fork.<ID-Nummer> angefordert hat. Der zugehörige Pfeil hat die Beschriftung getName.
  5. Klicken Sie doppelt auf getName. In der Thread-Ansicht verschiebt sich daraufhin die vertikale Markierung für die aktuelle Zeit, um die Vorgänge im gesamten Programm beim Aufruf von getName anzuzeigen. Sie können sehen, dass die Anforderung erfolgreich war, denn der philo*-Thread, der die Anforderung gesendet hat, tritt nicht in den Status "Wartet auf Sperre" ein.
  6. Klicken Sie im Folgediagramm erneut auf Fork.<ID-Nummer> und blättern Sie in der Anzeige bis zu einer Anforderung getName von einem anderen philo*-Thread vor.
  7. Klicken Sie doppelt auf diese Instanz von getName. Die Markierung für die aktuelle Zeit zeigt an, dass der philo*-Thread, der die Anforderung sendet, Fork.<ID-Nummer> nicht abrufen kann und in den Status "Wartet auf Sperre" eintritt.

Bei dieser Instanz besteht das Problem in der Anforderung nach einer Sperre "Fork", die von einem anderen Thread gehalten wird. Überprüfen Sie die übrigen Threads, die am Ende in den Status "Wartet auf Sperre" wechseln, um festzustellen, ob dies auch für andere Instanzen gilt.

Jetzt wollen wir die Methode finden, die das Problem verursacht:

  1. Klicken Sie mit der rechten Maustaste auf die Profilerstellungsressource für den Durchgang und wählen Sie Öffnen mit > UML2-Thread-Interaktionen aus. Daraufhin wird die Ansicht "UML2-Folgediagramm" mit den Thread-Interaktionen geöffnet.
  2. Erweitern Sie im Monitor für Profilerstellung die Anzeige für Ihre Profilerstellungsressource. Erweitern Sie dann die Anzeige für die Einträge "Thread-Analyse" und "Aufruf-Stack".
  3. Klicken Sie in der Thread-Ansicht mit den Namen der Threads doppelt auf den ersten philo*-Thread, der in den Status "Wartet auf Sperre" eintritt. In der Ansicht "Thread-Interaktionen" werden jetzt nur Informationen zu diesem Thread angezeigt.
  4. Blättern Sie zum Ende der Informationen für den Thread vor und klicken Sie doppelt auf die letzte vom Thread ausgeführte Methode: die Methode run. Der Aufruf-Stack im Monitor für Profilerstellung zeigt alle zu diesem Zeitpunkt ausgeführten Aufrufe im Stack an.
  5. Im Aufruf-Stack sehen Sie, dass der Thread, der die Sperre hält, die Methode Sleep in Philosopher.java aufgerufen hat oder ebenfalls auf eine Sperre wartet und somit keine weiteren Aktionen ausführt.
  6. Überprüfen Sie die übrigen Threads, die am Ende des Durchgangs auf eine Sperre warten. Die Methode Sleep in Philosopher.java ist oft im Aufruf-Stack enthalten und könnte das Problem sein.

Da die Methode Sleep als Fehlerursache vermutet wird, wollen wir uns den Code anschauen:

  1. Klicken Sie im Aufruf-Stack mit der rechten Maustaste auf eine Instanz von Sleep(int) void [Philosopher.java] und wählen Sie Quelle öffnen aus. Die Quelle wird im Editor an der Position der Klasse Sleep geöffnet.
  2. Untersuchen Sie den Code. Beachten Sie, dass die Methode Sleep aus der Methode run heraus aufgerufen wird. Zunächst wird trace aufgerufen, um die Nachricht "got left..." auszugeben. Anschließend wird Sleep aufgerufen. Wenn wir den Aufruf von Sleep auf Kommentar setzen, lässt sich die gegenseitige Sperre möglicherweise vermeiden.
  3. Setzen Sie Sleep auf Kommentar.
  4. Wählen Sie Datei > Speichern aus.
Erstellen Sie jetzt erneut das Profil für Ihr Programm.

Diesmal wird das Programm ohne eine gegenseitige Sperre ausgeführt und gibt folgendes auf der Konsole aus:

HeadWaiter reports all philosophers have finished dining normally

Wie Sie sehen, zeigen die Thread-Ansicht und andere Ansichten an, was während der Programmausführung mit den Threads geschieht. Ihre Aufgabe ist es, ausgehend von Ihrer Kenntnis des Programms die Analyse durchzuführen und die gegenseitige Sperre aufzulösen.

Lesen Sie zum Abschluss des Lernprogramms die Informationen in der Zusammenfassung.

Nutzungsbedingungen | Feedback
(C) Copyright IBM Corporation 2000, 2005. Alle Rechte vorbehalten.