スレッド化の問題

ウィジェット・ツールキットを使用している場合は、プラットフォーム GUI イベントの読み取りおよびディスパッチに使用される基本的なスレッド・モデルを理解することが重要です。 UI スレッドを実装すると、これらのコードで Java スレッドを使用するときにアプリケーションが従う必要がある規則に影響があります。

ネイティブ・イベントのディスパッチ

GUI アプリケーションでは、言語または UI ツールキットに関係なく、OS プラットフォームは GUI イベントを検出し、それをアプリケーション・イベント・キューに入れます。 OS プラットフォームごとに仕組みは微妙に異なりますが、基本は同じです。ユーザーがマウスをクリックしたり、文字を入力したり、ウィンドウを表示すると、 OS はマウス・クリック、キー・ストローク、ウィンドウ・ペイント・イベントなどのアプリケーション GUI イベントを生成します。 OS は各イベントを受け取るウィンドウおよびアプリケーションを判別して、アプリケーションのイベント・キューにそのイベントを入れます。

すべてのウィンドウ表示 GUI アプリケーションの基本構造はイベント・ループです。アプリケーションは、キューからの GUI イベントを読み取って適切に応答するだけのループを初期化し、開始します。このイベントの 1 つが処理されている間に行われる作業は、GUI システムがユーザーにすぐに応答できるように、短時間で発生する必要があります。

UI イベントによってトリガーされる長時間の処理は、イベント・ループ・スレッドがすぐに戻り、アプリケーション・キューから次のイベントを取り出すことができるように、別のスレッド内で実行する必要があります。ただし、他のスレッドからウィジェットおよびプラットフォーム API にアクセスする場合は、明示ロックおよびシリアライゼーションによって制御する必要があります。アプリケーションがこれらの規則に従わない場合は、OS 呼び出しに失敗したり、GUI システム全体がロックされることがあります。

SWT UI のスレッド

SWT はプラットフォームで直接サポートされているスレッド化モデルに準拠します。アプリケーション・プログラムはメイン・スレッドでイベント・ループを実行し、このスレッドから直接イベントをディスパッチします。 UI スレッドは、 Display が作成されたスレッドです。その他のすべてのウィジェットは、UI スレッド内で作成する必要があります。

すべてのイベント・コードはアプリケーションの UI スレッドからトリガーされるため、イベントを処理するアプリケーション・コードはウィジェットに自由にアクセスして、特殊な技術を使わずにグラフィックス呼び出しを行うことができます。ただし、イベントに応答するのに長時間の処理を実行する場合、アプリケーションは計算スレッドを fork する役割を担います。

注: UI スレッドから実行する必要がある呼び出しが非 UI スレッドから実行された場合、 SWT は SWTException をトリガーします。

次に、SWT アプリケーションのメイン・スレッド (イベント・ループを含む) の構造を示します。

   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 ();
   }

ウィジェットが作成されて、シェルが開くと、シェル・ウィンドウが廃棄されるまで、アプリケーションは OS キューからイベントを読み取ってディスパッチします。キュー内に使用可能なイベントがない場合は、スリープして他のアプリケーションに実行の機会を与えるようにディスプレイに伝えます。

SWT は特殊なアクセス方法を使用して、バックグラウンド・スレッドからウィジェットおよびグラフィックス・コードを呼び出します。

非 UI スレッドからのコードの実行

非 UI スレッドから UI コードを呼び出す必要があるアプリケーションには、UI コードを呼び出す Runnable が必要です。Display クラスの syncExec(Runnable) および asyncExec(Runnable) メソッドは、イベント・ループ中に UI スレッド内でこれらの実行可能コードを実行するために使用されます。

次のコードのスニペットは、これらのメソッドの使用パターンを示します。

   // 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
   ...

asyncExec の使用中に、ウィジェットが実行可能コードから廃棄されるかどうかを調べることを推奨します。 asyncExec を呼び出してから、実行可能コードを実行するまでに、UI スレッドでその他の処理が発生することがあるため、実行可能コードを実行するまで、ウィジェットの状態は不明です。

ワークベンチおよびスレッド

SWT アプリケーションを最初から実装する場合は、イベント・ループの作成や、アプリケーションの計算スレッドを fork する判断を制御できるため、スレッド化規則は非常にわかりやすくなります。

ワークベンチにプラグイン・コードをコントリビュートしている場合は、物事がより複雑になります。以下の規則は、リリース間で例外もありますが、プラットフォーム UI クラスを使用するときの「使用規則」と見なすことができます。