NetBeansプロファイラーを使ってみる(スレッド監視)

NetBeansのプロファイラを使ってスレッド状態を監視するサンプルを紹介します。

NetBeansプロファイラのインストール

NetBeans プロファイラは、NetBeans5.5に加えて別途インストールする必要があります。
こちらからダウンロードできます。

ちなみにJDK1.4はプロファイラに対応していないのですが、Profiler用のJDK1.4.2が配布されているのでこれを使うとJDK1.4でもプロファイリングすることができます。
このページの「Modified 1.4.2 JVM」をダウンロードしてNetBeansから使用する。

これでNetBeans プロファイラを使用する準備が整います。

長い処理で画面描画が停止してしまう

「新規ファイル…」から、「Java GUIフォーム」カテゴリの、「JFrameフォーム」を作成します。
クラス名はEDTTest、パッケージはthreadとしました。
JFrameフォームをデザインします。JProgressBarとJButtonを置いて、こんな感じの画面デザインにします。
画面デザイン

ボタンのactionPerfomedイベントを記述します。
プログレスバーを0~100%まで徐々に増加させるように処理を記述します。

以下はEventDispatchスレッドで処理待ちをする悪い例です。


private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
  jButton1.setEnabled(false);
  //ダメダメなプログレスバーの処理
  jProgressBar1.setValue(0);
  while(jProgressBar1.getValue() < jProgressBar1.getMaximum()){
    jProgressBar1.setValue(jProgressBar1.getValue() + 1);
    try {
      Thread.sleep(20);
    } catch (InterruptedException ex) {
      ex.printStackTrace();
    }
  }
  jButton1.setEnabled(true);
}

実行し「一定時間待つ」ボタンを押してみます。プログレスバーが増加中はJFrameが描画されません。
一定時間待つと100%に表示されてしまいます。
実行結果
 ↓(途中の進捗状態が描画されない)
待った結果

また、待っている間に他のウィンドウで隠してからどかしてみると、隠された部分が再描画されません。
描画が停止してしまう

プロファイリング

待っている間に進捗状況が表示されないと、プログレスバーの意味がありません。
この原因を調べるために、プロファイラを使用してみます。

メニューから[プロファイル]-[主プロジェクトをプロファイル]を選択します。
プロジェクトで始めて実行する場合には、質問ダイアログが表示されますが、「了解」ボタンを押します。

「プロファイルタスクの選択」ダイアログでは、実施するプロファイリングタスクを選択します。
プロファイルタスクの選択
ここでは、「アプリケーションを監視」を選択し、「実行」ボタンを押します。
アプリケーションが実行されると、スレッドの状態を表すグラフが表示されます。
この状態で、アプリケーションの「一定時間待つ」を押すと、スレッドの表示が変化します。処理待ちの間は、AWT-EventQueue-0というスレッドが休眠中(紫色)の表示になるはずです。
スレッド監視グラフ1

AWT-EventQueueとはイベントディスパッチスレッドというスレッドで、Swingアプリケーションの描画処理を担当するスレッドです。このスレッドは大部分が待機状態にでないと、描画が乱れたりする不具合に繋がります。このスレッドで長時間かかる処理を記述してしまうと、長時間の処理中は、描画が行われなくなってしまいます。
現在のプログラムは、イベントディスパッチスレッドで処理待ちをしているために、画面描画も停止してしまうわけです。

別スレッドで処理を実行する

ボタンをもう1つ配置して、別の方法で処理を記述してみます。
ボタンをもう1つ配置


private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {
  jProgressBar1.setValue(0);
  jButton2.setEnabled(false);
  //別スレッドで時間のかかる処理を実施する
  Thread th = new Thread(){
    public void run(){
      try {
        while(jProgressBar1.getValue() < jProgressBar1.getMaximum()){
          SwingUtilities.invokeAndWait(new Runnable() {
            public void run() {
              jProgressBar1.setValue(jProgressBar1.getValue() + 1);
            }
          });
          Thread.sleep(20);
        }
        SwingUtilities.invokeAndWait(new Runnable() {
          public void run() {
            jButton2.setEnabled(true);
          }
        });
      } catch (InterruptedException ex) {
        ex.printStackTrace();
      } catch (InvocationTargetException ex) {
        ex.printStackTrace();
      }
    }
  };
  th.start();
}

このように別スレッドでプログレスバーを徐々に増加させる処理を記述すれば、意図したとおりに描画されます。
処理中でも描画される
プロファイル結果を見ると、イベントディスパッチスレッドはほとんど待機状態になっていることが分かります。
スレッド監視グラフ2

ちなみにSwingで別スレッドで処理させる場合には、SwingWorkerというクラスを用意するのが常套手段です。
http://java.sun.com/products/jfc/tsc/articles/threads/threads2.html
SwingWorkerはJDK6.0では標準クラスになっています。


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)