- PR -

HashMapの同期化について

投稿者投稿内容
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2003-06-10 23:35
unibon です。こんにちわ。

引用:

yamasaさんの書き込み (2003-06-10 18:37) より:
代わりにgetterRunnableを以下のように変更すると、
IllegalStateExceptionが投げられるようになると思います。


教えていただいたこのコードを、1CPU のコンピュータにおいて、
Windows 98 + JDK 1.4.1 の環境で動かしたところ、
おっしゃるように IllegalStateException が発生しました。
ありがとうございます。
(なお、Thread.yield(); がなくてもすぐに例外が発生しました。)

HashMap で同期化しないと、put したエントリ(キー)が見つからなくなるんですね。
もしかしたらそういう破綻の仕方なのかなと、わずかに思っていたのですが、
試すのがちょっと面倒だったので、今まではそこまで調べていませんでした。
しかし、今回、テストのために HashMap に put したキーを、
別の同期化した Set にも記録しておいて、
HashMap に put したことがそもそもなかったのか、
そうではなく put したことがあったのかが、
区別できるようにしました。
以下、長いですが、このコードを書きます。
コード:
import java.util.*;

public class SyncTester {

    public static void main(String[] args) {
        final int SIZE = 100000;
        final Random getterRandom = new Random(432987432987432L);
        final Random putterRandom = new Random(564165098897163L);

        // これは同期化されていないので破綻する。
        final Map map = new HashMap(10, 0.1F);

        // もしこっちを使うと同期化されているので正常に動作する。
        // final Map map = Collections.synchronizedMap(new HashMap(10, 0.1F));

        // デバッグ用に、put したキーを覚えておくための補助。
        final Set synchronizedSet = Collections.synchronizedSet(new HashSet());

        Runnable getterRunnable = new Runnable() {
            public void run() {
                while (true) {
                    int randomInt = getterRandom.nextInt(SIZE);
                    Integer key = new Integer(randomInt);
                    if (!synchronizedSet.contains(key)) {
                        continue;
                    }
                    Object value = map.get(key);
                    if (value == null) {
                        System.out.println("key = " + key + ", value = " + value);
                        throw new IllegalStateException();
                    }
                }
            }
        };
        Runnable putterRunnable = new Runnable() {
            public void run() {
                while (true) {
                    int randomInt = putterRandom.nextInt(SIZE);
                    Integer key = new Integer(randomInt);
                    Integer value = new Integer(randomInt);
                    if (!synchronizedSet.contains(key)) {
                        map.put(key, value);
                        synchronizedSet.add(key);
                    }
                }
            }
        };
        Thread getterThread = new Thread(getterRunnable);
        getterThread.start();
        Thread putterThread = new Thread(putterRunnable);
        putterThread.start();
    }
}

スキルアップ/キャリアアップ(JOB@IT)