Javaにおけるマルチスレッドwait()とnotify()メソッドに関する小さなエラーメモ

4291 ワード

最近Javaマルチスレッドの学習で、次のような問題が発生しました.
class Obj {
//            
    public static int flag = 0;

    public String name;

    Obj(String name) {
	this.name = name;
    }

    public synchronized void print() {
	System.out.print(name + "::");
	System.out.println("      ");
    }
}
public class ExceptionInWait {


    public static void main(String[] args) {
Obj o1 = new Obj("  ");
Obj o2 = new Obj("  ");


Thread t1 = new Thread() {
@Override
public void run() {
int flag = 1;
while (true) {
if (flag == Obj.flag) {
o1.print();
			Obj.flag = 0;
			o1.notifyAll(); //   1
		    } else {
			try {
			    o1.wait(); //   2
			} catch (InterruptedException e) {
			    e.printStackTrace();
			}
		    }
		}
	    }
	};


	Thread t2 = new Thread() {
	    @Override
	    public void run() {
		int flag = 0;
		while (true) {
		    if (flag == Obj.flag) {
			o2.print();
			Obj.flag = 1;
			o1.notifyAll(); //   3
		    } else {
			try {
			    o2.wait();//   4
			} catch (InterruptedException e) {
			    e.printStackTrace();
			}
		    }
		}
	    }
	};


	t1.start();
	t2.start();
    }


}

エラーが発生した箇所はjava初心者として、なぜこのようなエラーが発生したのか理解できませんでした.Oracleの公式チュートリアルのConcurrencyの章をよく読んでから、理解しました.
When a thread invokes d.wait, it must own the intrinsic lock for d

ただし、オブジェクトではprintメソッドがsynchronizedキーワードを持っているため、実行が完了すると、それぞれのロックが解放されます.
waitメソッドとnotifyメソッドを使用する前に、現在のスレッドが持っているロックオブジェクトを確認しなければなりません.ロックオブジェクトが存在しない場合、IllegalMonitorStateExceptionが発生します.ロックオブジェクトが存在するが、予想通りに設定されていない場合、プログラムの実行結果は予想とは異なります.
テキストリンク:http://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html
初めてエディタを使うので、エラーコードのフォーマットを直すのがおっくうで、下に正しいコードを貼ります
public class ExceptionInWait {

    public static void main(String[] args) {
	Obj o1 = new Obj("  ", 0);
	Obj o2 = new Obj("  ", 1);
	final Object lock = new Object();
	o1.setLock(lock);
	o2.setLock(lock);

	Thread t1 = new Thread() {
	    @Override
	    public void run() {
		while (true) {
		    o1.print();
		}
	    }

	};
	
	t1.setName("     ");

	Thread t2 = new Thread() {
	    @Override
	    public void run() {
		while (true) {
		    o2.print();
		}
	    }

	};
	
	t2.setName("     ");

	t1.start();
	t2.start();
    }

}

class Obj {

    public static int flag = 0;

    public int targetFlag;

    public String name;

    private Object lock;

    public void setLock(Object lock) {
	this.lock = lock;
    }

    Obj(String name, int targetFlag) {
	this.name = name;
	this.targetFlag = targetFlag;
    }

    public void print() {
	synchronized (lock) {
	    if (targetFlag == flag) {
		System.out.print(name + "::");
		System.out.println("      ");
		//Alter the condition
		if(Obj.flag==1){
		    Obj.flag=0;
		}else{
		    Obj.flag=1;
		}
		lock.notifyAll();//               ;wait notify              !
	    }else{
		try {
		    lock.wait();
		} catch (InterruptedException e) {
		    e.printStackTrace();
		}
	    }
	}
    }
}