Hinweise zur Verwendung von Threads

Wenn Sie mit einem Toolkit für Fensterobjekte arbeiten, müssen Sie das zu Grunde liegende Thread-Modell kennen, mit dem Ereignisse der Plattform-GUI gelesen und zugeteilt werden. Die Implementierung des UI-Threads hat Einfluss auf die Regeln, die Anwendungen bei der Verwendung von Java-Threads in ihrem Code befolgen müssen.

Native Ereigniszuteilung

Unterhalb einer GUI-Anwendung stellt die Betriebssystemplattform - unabhängig von ihrer Sprache oder dem UI-Toolkit - GUI-Ereignisse fest und stellt diese in die Ereigniswarteschlangen von Anwendungen. Obwohl sich die Mechanismen zwischen den einzelnen Betriebssystemen leicht unterschieden, sind die Grundlagen ähnlich. Sobald der Benutzer mit der Maus klickt, Zeichen eingibt oder in Fenstern navigiert, generiert das Betriebssystem GUI-Ereignisse wie Mausklicks, Tastatureingaben oder Fensterfüllungen. Es ermittelt, welches Fenster und welche Anwendung das jeweilige Ereignis empfangen sollte, und stellt das Ereignis in die Ereigniswarteschlange der Anwendung.

Die zu Grunde liegende Struktur jeder GUI-Anwendung mit Fensterfunktion ist eine Ereignisschleife. Anwendungen initialisieren und starten dann eine Schleife, die die GUI-Ereignisse einfach aus der Warteschlange liest und entsprechend reagiert. Alle Operationen zur Verarbeitung dieser Ereignisse müssen schnell ausgeführt werden, damit das GUI-System für den Benutzer empfangsbereit bleibt.

Lange Operationen, die durch GUI-Ereignisse ausgelöst werden, sollten in einem separaten Thread ausgeführt werden, damit der Thread der Ereignisschleife schnell zurückkehren und das nächste Ereignis aus der Warteschlange der Anwendung entnehmen kann. Der Zugriff auf die Fensterobjekte und Plattform-API aus anderen Threads muss jedoch durch explizites Sperren und eine serielle Anordnung gesteuert werden. Eine Anwendung, die diese Regeln nicht befolgt, kann einen Betriebssystemaufruf für das Fehlschlagen oder - schlimmer noch - das Sperren des gesamten GUI-Systems verursachen.

SWT-UI-Thread

SWT folgt dem Thread-Modell, das durch die Plattformen direkt unterstützt wird. Das Anwendungsprogramm führt die Ereignisschleifen in seinem Haupt-Thread aus und teilt die Ereignisse direkt aus diesem Thread zu. Der UI-Thread ist der Thread, in dem die Anzeige erstellt wurde. Alle anderen Fensterobjekte müssen im UI-Thread erstellt werden.

Da der gesamte Ereigniscode vom UI-Thread der Anwendung ausgelöst wird, kann der Anwendungscode, der Ereignisse verarbeitet, frei auf die Fensterobjekte zugreifen und Grafikaufrufe ausgeben, ohne dass besondere Techniken erforderlich sind. Die Anwendung ist jedoch für die Aufspaltung der Berechungs-Threads zuständig, wenn infolge eines Ereignisses längere Operationen ausgeführt werden müssen.

Hinweis: SWT löst für alle Aufrufe aus einem Nicht-UI-Thread, die aus dem UI-Thread erfolgen müssten, eine Ausnahmebedingung SWTException aus.

Der Haupt-Thread für eine SWT-Anwendung (inklusive Ereignisschleife) hat die folgende Struktur:

   public static void main (String [] args) {
      Display display = new Display ();
      Shell shell = new Shell (display);
      shell.open ();
      // start the event loop. We stop when the user has done
      // something to dispose our window.
      while (!shell.isDisposed ()) {
         if (!display.readAndDispatch())
            display.sleep();
      }
      display.dispose ();
   }

Sobald die Fensterobjekte erstellt wurden und die Shell geöffnet ist, liest die Anwendung Ereignisse aus der Warteschlange des Betriebssystem und teilt diese zu, bis das Shell-Fenster entfernt wird. Wenn keine Ereignisse in der Warteschlange vorhanden sind, wird eine Anweisung zur Inaktivierung der Anzeige ausgegeben, damit andere Anwendungen ausgeführt werden können.

SWT bietet spezielle Zugriffsmethoden, mit denen Fensterobjekte und Grafikcode von einem Hintergrund-Thread aus aufgerufen werden können.

Code aus einem Nicht-UI-Thread ausführen

Anwendungen, die UI-Code aus einem Nicht-UI-Code heraus aufrufen sollen, müssen eine ausführbare Ressource zur Verfügung stellen, die den UI-Code aufruft. Mit den Methoden syncExec(Runnable) und asyncExec(Runnable) in der Klasse Display werden diese ausführbaren Ressourcen während der Ereignisschleife im UI-Thread ausgeführt.

Der folgende Codeausschnitt veranschaulicht das Muster für die Verwendung dieser Methoden:

   // do time-intensive computations
   ...
   // now update the UI. We don't depend on the result,
   // so use async.
   display.asyncExec (new Runnable () {
      public void run() {
         if (!myWindow.isDisposed())
            myWindow.redraw();
      }
   });
   // now do more computations
   ...

Es gehört zur guten Praxis, zu überprüfen, ob Ihr Fensterobjekt bei der Verwendung von 'asyncExec' von innerhalb der ausführbaren Ressource entfernt wird. Da zwischen dem Aufruf von asyncExec und der Ausführung Ihrer ausführbaren Funktion andere Dinge im UI-Thread passieren können, können Sie nie mit Sicherheit sagen, in welchem Status sich Ihre Fensterobjekte zum Zeitpunkt der Ausführung Ihrer ausführbaren Funktion befinden werden.

Die Workbench und Threads

Die Thread-Regeln sind sehr eindeutig, wenn Sie eine SWT-Anwendung von Grund auf implementieren, weil Sie die Erstellung der Ereignisschleife und die Entscheidung über die Aufspaltung von Berechnungs-Threads in Ihrer Anwendung steuern.

Bei der Ergänzung der Workbench um Plug-in-Codes werden die Dinge allerdings ein wenig komplizierter. Die folgenden Regeln können als Verwendungsregeln für die Verwendung der Benutzerschnittstellenklassen der Plattform angesehen werden, obwohl es zwischen einzelnen Releases zu Ausnahmen zu diesen Regeln kommen kann: