株式会社イーヴ

EeBlog(テクニカルブログ)

TOP > EeBlog > 第60回 割り込み

第60回 割り込み

今回のテーマは「割り込み」です。

前回は、Swingアプリケーションで時間のかかる処理はバックグラウンドスレッドで実行することについて書きました。
ですが、あまりにも時間のかかる処理は、途中でキャンセルしたい場合があるでしょう。
今回は、そのために、そのスレッドに対して割り込みを行うことを考えてみます。

スレッドに対して割り込みを行うには、そのスレッドのinterruptメソッドを実行します。
現在のスレッドが割り込まれているかどうかを調べるにはinterruptedメソッドを実行します。
スレッドが割り込まれたときに特定の処理を実行したい場合は、割り込まれているかどうかを頻繁にチェックする必要があります。

次のサンプルコードはキャンセル可能なタスクを実行するSwingアプリケーションです。

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


 import javax.swing.JButton;
 import javax.swing.JFrame;
 import javax.swing.JPanel;
 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 JButton runButton = new JButton("処理開始");
     private JButton cancelButton = new JButton("キャンセル");
     private Thread thread;


     public MainWindow() {
         runButton.addActionListener(this);
         cancelButton.addActionListener(this);
         cancelButton.setEnabled(false);
         jPanel.add(runButton);
         jPanel.add(cancelButton);
         setContentPane(jPanel);
         setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
         setSize(300, 75);
         setLocationRelativeTo(null);
         setVisible(true);
     }


     public void actionPerformed(ActionEvent actionEvent) {
         if (runButton.equals(actionEvent.getSource())) {
             runButton.setEnabled(false);
             cancelButton.setEnabled(true);
             thread = new Thread(this);
             thread.start();
         }
         if (cancelButton.equals(actionEvent.getSource())) {
             thread.interrupt();
         }
     }


     public void run() {
         for (int i = 0; i < 10000000; i++) {
             if (Thread.interrupted()) {
                 break;
             }
         }
         SwingUtilities.invokeLater(new Runnable() {
             public void run() {
                 runButton.setEnabled(true);
                 cancelButton.setEnabled(false);
             }
         });
     }
 }

画面には「処理開始」ボタンと「キャンセル」ボタンがあります。
「処理開始」ボタンを押下すると、バックグラウンドスレッドを起動し、時間のかかる処理を実行します。(一定回数ループするだけ)
「キャンセル」ボタンを押下すると、そのバックグラウンドスレッドに対して割り込みを行います。
バックグラウンドスレッドでは、割り込まれた場合に、ループを中断するようにしています。

ちなみに、setEnabledメソッドはボタンを有効または無効にします。
処理実行中は「処理開始」ボタンを無効にし、「キャンセル」ボタンを有効にしています。
処理が完了した場合、またはキャンセルされた場合は、「処理開始」ボタンを有効にし、「キャンセル」ボタンを無効にしています。
これは、2重処理を防ぐために行っています。
有効、無効の切り替えは、例によってイベントディスパッチスレッド上で行うことに注意してください。