Lock/Conditionのサンプル

追記:「見せかけの起動」に対応しました。2008/12/6
http://d.hatena.ne.jp/nowokay/20081206#1228542137


wait/notifyでスレッド間の同期を行ったのですが、wait/notifyは対象オブジェクトでsynchronizedする必要がありました。
ということは、逆にいうとsynchronizedブロックひとつにつきひとつの同期オブジェクトしか使えないということです。


そこで、Lock/Conditionを使うともっと柔軟に同期オブジェクトを使うことができます。
とりあえず、wait/notifyサンプルと同じことをLock/Conditionでやってみました。


まず、Lockオブジェクトを用意します。

Lock lock = new ReentrantLock();


このLockオブジェクトのロック中に使える同期オブジェクトを、newConditonメソッドで得ます。

Condition condition = lock.newCondition();


また、「見せかけの起動」に対応するため、実行再開条件をあらわすフラグも用意しておきます。

boolean flag = false;

waitメソッドと同じ働きをするのがawaitメソッドです。awaitメソッドは再開条件の確認も行うようにします。

while(!flag){
    condition.await();
}


waitメソッドでsynchronizedが必要だったように、awaitメソッドではその元になったロックオブジェクトをlockしておく必要があります。

lock.lock();


notifyメソッドの代わりはsignalメソッドです。awaitの場合と同様にlockが必要です。ここで、waitの再開条件がみたせるようにしておきます。

try{
    lock.lock();
    flag = true;
    condition.signal();
}finally{
    lock.unlock();
}


ということでソース

import java.awt.FlowLayout;
import java.awt.event.*;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import javax.swing.*;

public class LockConditionSample {
    public static void main(String[] args){
        JFrame f = new JFrame("Lockサンプル");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLayout(new FlowLayout());

        final JTextField tf = new JTextField();
        tf.setColumns(12);
        f.add(tf);

        //ロック用オブジェクト
        final Lock lock = new ReentrantLock();
        final Condition condition = lock.newCondition();
        final boolean[] flag = {false};
        //スレッド
        final Thread t = new Thread(){
            @Override
            public void run() {
                try {
                    lock.lock();
                    for(int i = 3; i > 0; --i){
                        tf.setText("カウント" + i);
                        Thread.sleep(1000);
                    }
                    tf.setText("待機中");
                    flag[0] = false;
                    while(!flag[0]){
                        condition.await();
                    }
                    tf.setText("きた!");
                } catch (InterruptedException ex) {
                    tf.setText("中断");
                }finally{
                    lock.unlock();
                }
            }

        };
        t.start();

        JButton b;
        //再開ボタン
        b = new JButton("再開");
        f.add(b);
        b.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                //ボタン押されたらnotify
                try{
                    lock.lock();
                    flag[0] = true;
                    condition.signal();
                }finally{
                    lock.unlock();
                }
            }
        });

        //中断
        b = new JButton("中断");
        f.add(b);
        b.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                //ボタン押されたらinterrupt
                t.interrupt();
            }
        });

        f.pack();
        f.setVisible(true);
    }
}