なぜこれが起こるのでしょうか?問題は、モニターオブジェクトが確かにnullではないことですが、それでもこの例外は頻繁に発生します。
_Java.lang.IllegalMonitorStateException: (m=null) Failed to get monitor for (tIdx=60)
at Java.lang.Object.wait(Object.Java:474)
at ...
_
これを引き起こすコードは、単純なプールソリューションです。
_ public Object takeObject() {
Object obj = internalTakeObject();
while (obj == null) {
try {
available.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
obj = internalTakeObject();
}
return obj;
}
private Object internalTakeObject() {
Object obj = null;
synchronized (available) {
if (available.size() > 0) {
obj = available.keySet().iterator().next();
available.remove(obj);
synchronized (taken) {
taken.put(obj, Boolean.valueOf(true));
}
}
}
return obj;
}
public void returnObject(Object obj) {
synchronized (taken) {
taken.remove(obj);
}
synchronized (available) {
if (available.size() < size) {
available.put(obj, Boolean.valueOf(true));
available.notify();
}
}
}
_
何か不足していますか?
[〜#〜] edit [〜#〜]:例外はavailable.wait();
行で発生します。
Object.waitのjavadocを参照してください。
特に、「現在のスレッドがこのオブジェクトのモニターを所有している必要があります。」および「[スロー] IllegalMonitorStateException-現在のスレッドがオブジェクトのモニターの所有者でない場合」つまり、wait onを呼び出すオブジェクトで同期する必要があります。
あなたのコードは次のようになります:
synchronized (available) {
available.wait();
}
available.wait();
はsynchronized(available)セクションにある必要があります
「IllegalMonitorStateException」を取得しています
available.wait()
wait()メソッドを呼び出す現在のスレッドは、「使用可能な」オブジェクト参照によって参照されるオブジェクトのモニターの所有者ではないためです。
スレッドがオブジェクトのモニターの所有者になるには、3つの方法があります。
各シナリオの簡単なサンプルコード。 3つのコードスニペットはすべて、タイプごとに個別のクラスであり、コードをコピーして実行するだけです。各ケースで何が起こっているのかを説明するために、コードにコメントを大幅に追加しました。コメントが多すぎる場合。コードをより簡潔にするためにそれらを削除してください。
また、最初にmain()メソッドのコードを読んで、threadOneとthreadTwoについて最初に考えてください。
そのオブジェクトの同期インスタンスメソッドを実行する。
import static Java.lang.System.out;
public class SynchronizedInstanceMethodClass {
synchronized void synchronizedInstanceMethod() { // threadOne acquire the monitor for "this" and continue.
try {
out.println("EVENT #1 threadOne is about to strat waiting on the "
+"monitor it already has - [\"this\"]....");
this.wait(); // The threadOne already have the monitor for "this",
// just release the monitor and go and wait threadOne.
out.println("EVENT #3 Notify received and continue execution...");
} catch (InterruptedException interruptedException) {
interruptedException.printStackTrace();
}
}
synchronized void notifierForAllThreads() { // threadTwo acquire the monitor for "this",
// which was released by threadOne when it went to waiting and contine.
out.println("EVENT #2 threadTwo is about to notify all threads(including threadOne) "
+" waiting on the monitor of -[\"this\"]....");
this.notifyAll(); // threadTwo who owns the monitor on "this" notifies all
// threads waiting on "this" and releases the monitor
}
public static void main(String [] args) {
SynchronizedInstanceMethodClass mc = new SynchronizedInstanceMethodClass();
Thread threadOne = new Thread(() -> {mc.synchronizedInstanceMethod();});
Thread threadTwo = new Thread(() -> {mc.notifierForAllThreads();});
threadOne.start(); // Start the waiting of Thread one
threadTwo.start(); // Notify the waiting threadOne
}
}
オブジェクトで同期する同期ブロックの本体を実行する。
import static Java.lang.System.out;
public class SynchronizedBlockClass {
void synchronizedBlockInstanceMethod() {
synchronized (this) { // threadOne acquire the monitor for "this" and continue.
try {
out.println("EVENT #1 threadOne is about to strat waiting on the "
+"monitor it already has - [\"this\"]....");
this.wait(); // The threadOne already have the monitor for "this",
// just release the monitor and go and wait threadOne.
out.println("EVENT #3 Notify received and continue execution...");
} catch (InterruptedException interruptedException) {
interruptedException.printStackTrace();
}
}
}
void synchronizedBlockNotifierForAllThreads() {
synchronized (this) { // threadTwo acquire the monitor for "this",
// which was released by threadOne when it went to waiting and continue.
out.println("EVENT #2 threadTwo is about to notify all threads(including threadOne) "
+" waiting on the monitor of -[\"this\"]....");
this.notifyAll(); // threadTwo who owns the monitor on "this" notifies all
// threads waiting on "this" and releases the monitor
}
}
public static void main(String [] args) {
SynchronizedBlockClass mc = new SynchronizedBlockClass();
Thread threadOne = new Thread(() -> {mc.synchronizedBlockInstanceMethod();});
Thread threadTwo = new Thread(() -> {mc.synchronizedBlockNotifierForAllThreads();});
threadOne.start(); // Start the waiting of Thread one
threadTwo.start(); // Notify the waiting threadOne
}
}
Classクラスのオブジェクトの場合、そのクラスの同期静的メソッドを実行します。
import static Java.lang.System.out;
public class StaticClassReferenceClass {
void synchronizedBlockInstanceMethod() {
synchronized (StaticClassReferenceClass.class) { // threadOne acquire the monitor for class literal and continue.
try {
out.println("EVENT #1 threadOne is about to strat waiting on the "
+"monitor it already has - [StaticClassReferenceClass.class]....");
StaticClassReferenceClass.class.wait(); // The threadOne already have the monitor for the class literal,
// So it just release the monitor and go and wait.
out.println("EVENT #3 Notify received and continue execution...");
} catch (InterruptedException interruptedException) {
interruptedException.printStackTrace();
}
}
}
void synchronizedBlockNotifierForAllThreads() {
synchronized (StaticClassReferenceClass.class) { // threadTwo acquire the monitor for the class literal,
// which was released by threadOne when it went to waiting.
out.println("EVENT #2 threadTwo is about to notify all threads(including threadOne) "
+" waiting on the monitor of -[StaticClassReferenceClass.class]....");
StaticClassReferenceClass.class.notifyAll(); // threadTwo who owns the monitor on the class literal notifies all
// threads waiting on it and releases the monitor
}
}
public static void main(String [] args) {
StaticClassReferenceClass mc = new StaticClassReferenceClass();
Thread threadOne = new Thread(() -> {mc.synchronizedBlockInstanceMethod();});
Thread threadTwo = new Thread(() -> {mc.synchronizedBlockNotifierForAllThreads();});
threadOne.start(); // Start the waiting of Thread one
threadTwo.start(); // Notify the waiting threadOne
}
}
takeObject()メソッドは同期する必要があります。または、このメソッド内にsynchronizedブロックを記述する必要があります。このためにコンパイル時の例外が発生することを願っています。