EeBlog(テクニカルブログ)

第58回 Swingのスレッドポリシー

今回のテーマは「Swingのスレッドポリシー」です。

今回はSwingアプリケーションを実装するうえで知っておくべきスレッドポリシーについて書きます。 通常のSwingアプリケーションは、ユーザーのジェスチャーによって生成されたイベントに応じて、処理を実行します。 すべてのイベントはイベントディスパッチスレッドという1つのスレッド上で実行されます。したがって、イベントディスパッチスレッド上でイベント処理が実行中の場合、ほかのイベントは受け付けません。 このような仕様になっているのはSwingがスレッドセーフではないからです。

次のサンプルコードは単純な入力画面を表示するプログラムです。 画面にはテキストフィールドとボタンのみがあります。

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

 import javax.swing.JButton;
 import javax.swing.JFrame;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JTextField;
 import javax.swing.SwingUtilities;
 import javax.swing.UIManager;

 public class MainWindow extends JFrame implements ActionListener {

     private static final long serialVersionUID = 1L;

     public static void main(String[] args) {
         SwingUtilities.invokeLater(new Runnable() {
             public void run() {
                 try {
                     UIManager.setLookAndFeel(UIManager
                                             .getSystemLookAndFeelClassName());
                 } catch (Exception e) {}
                 new MainWindow();
             }
         });
     }

     private JPanel jPanel = new JPanel();
     private JTextField jTextField = new JTextField(20);
     private JButton jButton = new JButton("button");

     public MainWindow() {
         jButton.addActionListener(this);
         jPanel.add(jTextField);
         jPanel.add(jButton);
         setContentPane(jPanel);
         setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
         setSize(500, 75);
         setLocationRelativeTo(null);
         setVisible(true);
     }

     public void actionPerformed(ActionEvent actionEvent) {
         JOptionPane.showMessageDialog(this, jTextField.getText());
     }
 }

Swingのスレッドポリシーには、すべてのSwingコンポーネントと関連クラスには、イベントディスパッチスレッド上でアクセスする、とあります。
サンプルコードでは、画面やテキストフィールドやボタンはSwingのコンポーネントになります。

mainメソッドの処理はイベントディスパッチスレッド上の処理ではないので、画面生成処理はイベントディスパッチスレッド上で実行されるように制御を渡すようにします。
そのためには、SwingUtilitesクラスのinvokeLaterメソッドを使用します。
invokeLater メソッドは、Runnable がイベントディスパッチスレッド上で実行されるようにスケジュールします。

ユーザーがボタンを押下すると、actionPerformedメソッドが実行されますが、これはイベントディスパッチスレッドで実行されます。

スレッドポリシーにしたがって、コンポーネントへのアクセスはイベントディスパッチスレッド上で実行すれば、コンポーネントに対して複数のスレッドからのアクセスは発生しないことになります。