JavaFX 2.0でアプリケーション作成(その6) - torutkのブログの続きです。
Semaphoreクラスのacquireメソッドは、セマフォの許可数が1以上あれば、許可数を1減じてリターンしますが、許可数が0であれば、許可数が1以上になるまで(すなわちreleaseメソッドが呼ばれるまで)ブロックします。
JavaFXアプリケーション・スレッドでSemaphoreのacquireメソッドを呼び、ブロックされると、GUIが固まった状態になってしまいます。そこで、ブロックされるメソッドや処理に時間のかかるメソッドを呼ぶときは、JavaFXアプリケーション・スレッドとは別のスレッド(バックグラウンドスレッド)で実行します。
今回は、JavaFX 2アプリケーションでバックグラウンドスレッドの使い方を調べます。
ドキュメント
JavaFX公式サイトのドキュメントページに掲載されているドキュメントです。PDF版も用意されています。
このドキュメントによると、JavaFX 2.0ライブラリで用意されているバックグラウンドスレッド用のAPIは、javafx.concurrentパッケージのTaskクラスまたはServiceクラスとなります。どちらのクラスもabstractで、同パッケージのWorkerインタフェースを実装する形となっています。アプリケーション側でサブクラスを定義して使用します。
なお、Web上での情報では、Javaの標準機能でスレッドを生成し、javafx.application.PlatformクラスのrunLaterメソッドで別スレッドからJavaFX APIを呼ぶコーディングも見かけます。これは、SwingにおけるSwingUtilities.invokeLaterメソッドと同じ目的と思われます。
Taskクラス
Taskクラスはjava.util.concurrent.FutureTaskのサブクラスとして定義されています。
よって、最低限callメソッドを実装すれば使用できます。Taskをバックグラウンドスレッドで動かすためには、ふつうのスレッドを生成するのと同様、Threadクラスまたはjava.util.concurrentパッケージを使います。
ただし、callメソッドは別スレッドで実行するので、callメソッドの内部でJavaFXのAPIを呼ぶことができません。別スレッドで実行した結果をJavaFXのシーングラフに反映させるには、Taskクラスに用意されているupdateProgress/updateMessage/updateTitleを使います。callメソッドでこの3つのメソッドのいずれかを呼ぶと、Taskの対応するプロパティの値が変化します。したがって、このプロパティの変化をシーングラフのいずれかにあらかじめバインドしておくことで、Taskの実行に応じて表示を変えるということです。
Taskクラスの注意点は、Taskクラスのインスタンスを生成し、いったん実行した後は、同じインスタンスを再度実行しようとすると例外を投げる点です。つまり、Taskクラスのインスタンスは1回だけしか実行できません。毎回インスタンスを生成する必要があります。
次回
セマフォの獲得(ブロッキング呼び出し)を行うSemaphore.acquireメソッドを別スレッドで実行する機能を追加します。GUIとして、ボタンの追加、別スレッドが実行している間はProgressBarを表示させる予定です。