JavaFXでThreadを使用した際にハマったポイントを記載します。
Threadの処理完了をjoinで待つとその間GUIが再描画されなかったので、原因と対応策について調べました。調べた内容を忘れないように備忘録に残したいと思います。
環境
- CentOS リリース 6.10 (Final)
- カーネル Linux 2.6.32-754.el6.x86_64
- java version 1.8.0_241
- Java(TM) SE Runtime Enviroment (build 1.8.0_241-b07)
- Java HotSpot(TM) 64-Bit Server VM (build 25.241-b07, mixed mode)
java.lang.Thread.join を使うとGUIが再描画されない!?
何か重い処理をするときに「しばらくお待ちください」とダイアログを表示したいと思い、以下のような実装を行いました。
showWaitDialog(); // 「しばらくお待ちください」ダイアログを表示 Thread t = new Thread(()-> { // スレッド作成 Thread.sleep(10000); // 重い処理の代わり }); t.start(); // スレッド開始 t.join(); // スレッド終了まで待機 closeWaitDialog(); // ダイアログを閉じる
実行してみると「showWaitDialog()」でダイアログが描画されなかった。
原因
「java.lang.Thread」クラスの「join」関数は、ブロッキング呼び出しで、バックグラウンドスレッドが完了するまでFXアプリケーションスレッドをブロックします。
その結果、UI再描画やユーザー入力に応答しなくなり、今回表示したかったダイアログも表示されませんでした。
解決案:Taskを使用する
今回やりたかったことを実現するには、「Task」を使用することで簡単に実現できました。
showWaitDialog(); // 「しばらくお待ちください」ダイアログを表示 Task<Void> task = new Task<Void>() { @Override public void call() throws Exception { Thread.sleep(10000); // 重い処理の代わり return null; } }; task.setOnSucceeded(e -> { // Task正常終了時イベント closeWaitDialog(); // ダイアログを閉じる }); new Thread(task).start();
参考:
http://www.366service.com/jp/qa/d3f162116d8b3dc0c167c9562caff273
https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#join(long)
コメント