wait,notifyとnotifyallが注意すべき問題


waitを使用すると、notifyとnotifyallがjava.lang.I llegalMonitorStateExceptionを放出する可能性があります.
まずjava.lang.I llegalMonitorStateExceptionの説明を見てみましょう.
public class IllegalMonitorStateExceptionextends RuntimeException

                       ,                               。 

       : 
JDK1.0 

それから2段のコードを貼って、まずこの異常を投げ出すコードです.

package com.wikimore.threadtest;


/**
 * Hello world!
 * 
 */
public class App {

    private static Object lock = new Object();

    public static void main(String[] args) {
        Runnable r1 = new Runnable() {

            public void run() {
                System.out.println("t1 running");
                    try {
                        System.out.println("t1 waiting");
                        lock.wait();
                    }
                    catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("t1 running again");
                    lock.notifyAll();
            }
        };
        Thread t1 = new Thread(r1, "thread-1");
        Runnable r2 = new Runnable() {

            public void run() {
                System.out.println("t2 running");
                    try {
                        System.out.println("t2 waiting");
                        lock.wait();
                    }
                    catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("t2 running again");
                    lock.notifyAll();
            }
        };
        Thread t2 = new Thread(r2, "thread-2");

        Runnable r3 = new Runnable() {

            public void run() {
                System.out.println("t3 running");
                    try {
                        System.out.println("t3 waiting");
                        lock.wait(1000);
                    }
                    catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("t3 running again");
                    lock.notifyAll();
            }
        };
        Thread t3 = new Thread(r3, "thread-3");
        t1.start();
        t2.start();
        t3.start();
    }
}

このコードのスレッドはwaitメソッドとnotifyallメソッドを呼び出すとlockの同期ロックが得られず、モニタが指定されていないことに等しい.
例外を投げ出さないコードをもう1つください.

package com.wikimore.threadtest;

/**
 * Hello world!
 * 
 */
public class App {

    private static Object lock = new Object();

    public static void main(String[] args) {
        Runnable r1 = new Runnable() {

            public void run() {
                System.out.println("t1 running");
                synchronized (lock) {
                    try {
                        System.out.println("t1 waiting");
                        lock.wait();
                    }
                    catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("t1 running again");
                    lock.notifyAll();
                }
            }
        };
        Thread t1 = new Thread(r1, "thread-1");
        Runnable r2 = new Runnable() {

            public void run() {
                System.out.println("t2 running");
                synchronized (lock) {
                    try {
                        System.out.println("t2 waiting");
                        lock.wait();
                    }
                    catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("t2 running again");
                    lock.notifyAll();
                }
            }
        };
        Thread t2 = new Thread(r2, "thread-2");

        Runnable r3 = new Runnable() {

            public void run() {
                System.out.println("t3 running");
                synchronized (lock) {
                    try {
                        System.out.println("t3 waiting");
                        lock.wait(10000);
                    }
                    catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("t3 running again");
                    lock.notifyAll();
                }
            }
        };
        Thread t3 = new Thread(r3, "thread-3");
        t1.start();
        t2.start();
        t3.start();
    }
}

このコードはwaitメソッドを実行する前にlockの同期が得られるため、上記の異常は発生しません.
waitメソッドの実行時にロックが解放されるので、同期ブロックで実行しないと異常が発生する可能性があります.
waitに似たsleepメソッドは実行時にロックを解放しません.これはブロック防止に注意する必要があります.