株式会社イーヴ

EeBlog(テクニカルブログ)

TOP > EeBlog > 第59回 Swingのスレッドポリシー

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

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

Swingのスレッドポリシーには、イベントディスパッチスレッドでは時間のかかるタスクを実行しない、とあります。 イベントディスパッチスレッド上で処理が実行中は、他のイベントは受け付けません。 したがって、時間のかかる処理をイベントディスパッチスレッド上で実行すると、その処理中はユーザーは操作ができなくなってしまいます。 そのような時間のかかる処理はバックグラウンドスレッドで行うべきです。 バックグラウンドスレッドはイベントディスパッチスレッドではないので、処理の完了後にSwingコンポーネントにアクセスする必要がある場合は、イベントディスパッチスレッド上でアクセスすべきなので注意が必要です。

次のサンプルコードは時間のかかるタスクを実行するSwingアプリケーションです。(J2SE5.0以上対応)

import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.util.Vector;
 import java.util.concurrent.TimeUnit;


 import javax.swing.JButton;
 import javax.swing.JFrame;
 import javax.swing.JList;
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
 import javax.swing.SwingUtilities;
 import javax.swing.UIManager;


 public class MainWindow extends JFrame implements ActionListener, Runnable {


     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 Vector vector = new Vector();
     private JList jList = new JList(vector);
     private JScrollPane jScrollPane = new JScrollPane(jList);
     private JButton jButton = new JButton("処理開始");


     public MainWindow() {
         jButton.addActionListener(this);
         jPanel.add(jScrollPane);
         jPanel.add(jButton);
         setContentPane(jPanel);
         setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
         setSize(300, 200);
         setResizable(false);
         setLocationRelativeTo(null);
         setVisible(true);
     }


     public void actionPerformed(ActionEvent actionEvent) {
         new Thread(this).start();
         vector.add("処理を開始しました。");
         jList.updateUI();
     }


     public void run() {
         try {
             TimeUnit.SECONDS.sleep(5);
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
         SwingUtilities.invokeLater(new Runnable() {
             public void run() {
                 vector.add("処理が完了しました。");
                 jList.updateUI();
             }
         });
     }
 }

「処理開始」ボタンを押下すると、バックグラウンドスレッドを起動し、時間のかかるタスクを実行します。
時間のかかるタスクをバックグラウンドスレッド上で実行することで、その処理の完了を待たずに、再度処理を開始することが可能です。
また、画面には、処理開始時と処理完了時にメッセージを表示します。
複数のスレッドから同時にメッセージ表示を更新されないよう、イベントディスパッチスレッド上で更新されるようにしています。