私のプログラムでは、Javaでマルチスレッドを使用しています。スレッドを正常に実行しましたが、Thread.wait()
を使用しているときに、Java.lang.IllegalMonitorStateException
をスローしています。通知されるまでスレッドを待機させるにはどうすればよいですか?
Object.wait()
が機能するには、synchronized
ブロックにいる必要があります。
また、古い学校のスレッドパッケージではなく、同時実行パッケージを確認することをお勧めします。彼らはより安全であり、 扱いやすい です。
ハッピーコーディング。
編集
オブジェクトのロックを保持せずにアクセスしようとすると例外が発生するため、Object.wait()
を意味すると想定しました。
wait
はObject
ではなく、Thread
で定義されています。 Thread
のモニターは少し予測不能です。
すべてのJavaオブジェクトにはモニターがありますが、通常は専用のロックを使用することをお勧めします。
private final Object lock = new Object();
名前付きクラスを使用すると、わずかなメモリコスト(プロセスごとに約2K)で診断をわずかに読みやすくすることができます。
private static final class Lock { }
private final Object lock = new Lock();
オブジェクトをwait
またはnotify
/notifyAll
するには、synchronized
ステートメントでロックを保持する必要があります。また、ウェイクアップ条件を確認するためにwhile
ループが必要になります(スレッドについての適切なテキストを見つけて、理由を説明してください)。
synchronized (lock) {
while (!isWakeupNeeded()) {
lock.wait();
}
}
通知するには:
synchronized (lock) {
makeWakeupNeeded();
lock.notifyAll();
}
マルチスレッドを使用する場合は、Java言語とJava.util.concurrent.locks
ロック(およびJava.util.concurrent.atomic
)の両方を理解する価値があります。ただし、できる限りJava.util.concurrent
データ構造を使用してください。
私はこのスレッドがほぼ2歳であることを知っていますが、同じ問題でこのQ/Aセッションにも来たので、これを閉じる必要があります...
このillegalMonitorExceptionの定義を何度も読んでください...
IllegalMonitorExceptionは、スレッドがオブジェクトのモニターで待機しようとしたことを示すため、または指定されたモニターを所有せずにオブジェクトのモニターで待機している他のスレッドに通知しようとした場合にスローされます
この行は、2つの状況のいずれかが発生するとIllegalMonitorExceptionが繰り返し発生することを示しています。..
1>指定されたモニターを所有せずにオブジェクトのモニターで待機します。
2>指定されたモニターを所有せずに、オブジェクトのモニターで待機している他のスレッドに通知します。
一部の人は答えを持っているかもしれません...誰もがそうではない場合は、2つのステートメントをチェックしてください....
同期(オブジェクト)
object.wait()
両方のobjectが同じである場合... illegalMonitorExceptionは発生しません。
IllegalMonitorExceptionの定義をもう一度読んで、もう一度忘れないでください...
あなたのコメントに基づいて、次のようなことをしているようです。
Thread thread = new Thread(new Runnable(){
public void run() { // do stuff }});
thread.start();
...
thread.wait();
3つの問題があります。
他の人が言ったように、obj.wait()
は、現在のスレッドがobj
のプリミティブロック/ミューテックスを保持している場合にのみ呼び出すことができます。現在のスレッドがロックを保持していない場合、表示されている例外が発生します。
thread.wait()
呼び出しは、期待どおりの動作をしません。具体的には、thread.wait()
doesは、指定されたスレッドを待機させます。むしろ、他のスレッドがthread.notify()
またはthread.notifyAll()
を呼び出すまで、現在のスレッドを待機させます。
実際には、Thread
インスタンスを必要に応じて一時停止させる安全な方法はありません。 (これに最も近いJavaは非推奨のThread.suspend()
メソッドですが、Javadocで説明されているように、そのメソッドは本質的に安全ではありません。)
新しく起動したThread
を一時停止する場合、それを行う最善の方法は、CountdownLatch
インスタンスを作成し、ラッチでawait()
を呼び出して自分自身を一時停止することです。次に、メインスレッドは、ラッチでcountDown()
を呼び出して、一時停止したスレッドを続行します。
Thread
オブジェクトをロック/ミューテックスとして使用すると、以前のポイントに直交して問題が発生する場合があります。たとえば、Thread::join
のjavadocは次のように言います。
この実装は、
this.wait
を条件とするthis.isAlive
呼び出しのループを使用します。スレッドが終了すると、this.notifyAll
メソッドが呼び出されます。アプリケーションでは、wait
インスタンスでnotify
、notifyAll
、またはThread
を使用しないことをお勧めします。
IllegalMonitorStateExceptionを処理するには、呼び出しスレッドが適切なモニターを所有しているの場合にのみ、wait、notify、およびnotifyAllメソッドのすべての呼び出しが行われることを確認する必要があります。最も簡単な解決策は、これらの呼び出しを同期ブロック内に含めることです。 synchronizedステートメントで呼び出される同期オブジェクトは、モニターを取得する必要があるオブジェクトです。
モニターの概念を理解するための簡単な例を次に示します
public class SimpleMonitorState {
public static void main(String args[]) throws InterruptedException {
SimpleMonitorState t = new SimpleMonitorState();
SimpleRunnable m = new SimpleRunnable(t);
Thread t1 = new Thread(m);
t1.start();
t.call();
}
public void call() throws InterruptedException {
synchronized (this) {
wait();
System.out.println("Single by Threads ");
}
}
}
class SimpleRunnable implements Runnable {
SimpleMonitorState t;
SimpleRunnable(SimpleMonitorState t) {
this.t = t;
}
@Override
public void run() {
try {
// Sleep
Thread.sleep(10000);
synchronized (this.t) {
this.t.notify();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
あなたはコードを投稿していないので、私たちは暗闇の中で働いています。例外の詳細は何ですか?
スレッド内またはスレッド外からThread.wait()を呼び出していますか?
IllegalMonitorStateExceptionのjavadocによると、次のとおりだからです。
スレッドがオブジェクトのモニターで待機しようとしたこと、または指定されたモニターを所有せずにオブジェクトのモニターで待機している他のスレッドに通知しようとしたことを示すためにスローされます。
この答えを明確にするために、スレッドを待機するこの呼び出しも、同期ブロック内から呼び出されたにもかかわらず、IllegalMonitorStateExceptionをスローします。
private static final class Lock { }
private final Object lock = new Lock();
@Test
public void testRun() {
ThreadWorker worker = new ThreadWorker();
System.out.println ("Starting worker");
worker.start();
System.out.println ("Worker started - telling it to wait");
try {
synchronized (lock) {
worker.wait();
}
} catch (InterruptedException e1) {
String msg = "InterruptedException: [" + e1.getLocalizedMessage() + "]";
System.out.println (msg);
e1.printStackTrace();
System.out.flush();
}
System.out.println ("Worker done waiting, we're now waiting for it by joining");
try {
worker.join();
} catch (InterruptedException ex) { }
}
別のIllegalMonitorStateException
/スレッドから/にあるスレッドを起動しようとしたときにclass
name__を受け取りました。 Java 8
では、lock
name__関数の synchronized
name__機能の新しい同時実行APIinsteadを使用できます。
asynchronous
websocketトランザクションのオブジェクトをWeakHashMap
name__に既に保存していました。私の場合の解決策は、 lock
name__にConcurrentHashMap
name__オブジェクトを格納する をsynchronous
name__返信用にすることでもありました。 注condition.await
(.wait
ではありません)。
マルチスレッドを処理するには、Executors.newCachedThreadPool()
を使用して thread pool を作成しました。
Thread.wait()呼び出しは、Thread.classオブジェクトで同期するコード内で意味があります。私はそれがあなたが意味したものだとは思わない。
あなたが尋ねる
通知されるまでスレッドを待機させるにはどうすればよいですか?
現在のスレッドのみを待機させることができます。他のスレッドは、同意する場合にのみ穏やかに待機するように要求できます。
何らかの条件を待ちたい場合、ロックオブジェクトが必要です-Thread.classオブジェクトは非常に悪い選択です-それはシングルトンのAFAIKであるため、(Thread静的メソッドを除く)同期は危険です。
同期と待機の詳細については、トム・ホーティンがすでに説明しています。 Java.lang.IllegalMonitorStateException
は、同期されていないオブジェクトで待機しようとしていることを意味します。そうすることは違法です。
Java 7.0以前のバージョンを使用している人は、ここで使用したコードを参照できます。
public class WaitTest {
private final Lock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
public void waitHere(long waitTime) {
System.out.println("wait started...");
lock.lock();
try {
condition.await(waitTime, TimeUnit.SECONDS);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
lock.unlock();
System.out.println("wait ends here...");
}
public static void main(String[] args) {
//Your Code
new WaitTest().waitHere(10);
//Your Code
}
}
これが他の誰かを助けるかどうかはわかりませんが、これは上記のユーザー「Tom Hawtin-tacklin」の答えの私の問題を解決する重要な部分でした:
synchronized (lock) {
makeWakeupNeeded();
lock.notifyAll();
}
「ロック」がsynchronized()の引数として渡され、「ロック」.notifyAll()でも使用されるという事実だけです。
これらの2か所で作成したら、機能しました