追記:「スプリアスウェイクアップ」に対応しました。2008/12/6
http://d.hatena.ne.jp/nowokay/20081206#1228542137
ここまで、いろいろなロックを扱ったのですが、スレッド間での実行の制御も必要になります。
Javaでは、スレッド間の実行の制御にwait/notifyなどが用意されています。
ということで、wait/notifyなどのサンプルを作ってみました
カウントが0になると待機します。

このプログラムではロック用のオブジェクトを用意しています。また再開条件のフラグも用意します。
Object lock = new Object(); boolean flag = false;
待機するときは、オブジェクトのwaitメソッドを呼び出します。このオブジェクトに対してnotifyが呼び出されるまで、ここで待機します。このとき、notifyがなくてもwaitが再開してしまう「スプリアスウェイクアップ」という問題があるので、再開条件のチェックも必要です。
while(!flag){
lock.wait();
}
waitメソッドは、そのオブジェクトでのsynchronizedブロックで使う必要があります。
synchronized(lock){
「再開」ボタンを押すと「きた」と表示されます。

このとき、lockオブジェクトのnotifyメソッドを呼び出しています。notifyメソッドも、呼び出すときには対象オブジェクトでsynchronizedしておく必要があります。再開条件を満たすようにフラグも設定します。
synchronized (lock){
flag = true;
lock.notify();
}
カウントダウン時や待機中に中断ボタンを押すと「中断」となります。

ここでは、スレッドのinterruputメソッドを呼び出します。
t.interrupt();
そうすると、sleepメソッドかwaitメソッドの実行時にInterruputedExceptionが発生します。
catch (InterruptedException ex) {
tf.setText("中断");
}
このように、interrupt/InterruptedExceptionを使うと、スレッドをきれいに中断することができます。
スレッドを中断する命令としてstopメソッドがありますが、こちらは強制的にスレッドを中断します。finallyブロックは呼び出されますが、処理が中途半端になってしまう可能性があるので、非推奨になっています。
ところで、カウントダウン中に「再開」ボタンを押すとボタン処理が固まって、しばらくして「きた!」になります。

そういえば、waitメソッドもnotifyメソッドも、両方lockオブジェクトでsynchronizedしています。単純に考えると、このままではnotifyメソッドはロックが取得できず、デッドロックになってしまいそうです。
waitメソッドを呼び出すと、そのオブジェクトのロックが一時的に開放されます。そこでnotifyスレッドがロックを取得します。notifyを呼び出すと、そのnotifyスレッドがロックを開放してから、waitスレッドが再びロックを取得して実行が再開します。
ということで、ソース
import java.awt.*; import java.awt.event.*; import javax.swing.*; public class NotifySample { public static void main(String[] args){ JFrame f = new JFrame("Notifyサンプル"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setLayout(new FlowLayout()); final JTextField tf = new JTextField(); tf.setColumns(12); f.add(tf); //ロック用オブジェクト final Object lock = new Object(); final boolean[] flag = {false}; //スレッド final Thread t = new Thread(){ @Override public void run() { synchronized (lock){ try { for(int i = 3; i > 0; --i){ tf.setText("カウント" + i); Thread.sleep(1000); } tf.setText("待機中"); flag[0] = false; while(!flag[0]){ lock.wait(); } tf.setText("きた!"); } catch (InterruptedException ex) { tf.setText("中断"); } } } }; t.start(); JButton b; //再開ボタン b = new JButton("再開"); f.add(b); b.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { //ボタン押されたらnotify synchronized (lock){ flag[0] = true; lock.notify(); } } }); //中断 b = new JButton("中断"); f.add(b); b.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { //ボタン押されたらinterrupt t.interrupt(); } }); f.pack(); f.setVisible(true); } }
