私のプログラムでは、Javaでマルチスレッドを使用しています。スレッドは正常に実行されましたが、使用Thread.wait()
しているとスローされjava.lang.IllegalMonitorStateException
ます。通知されるまでスレッドを待機させるにはどうすればよいですか?
私のプログラムでは、Javaでマルチスレッドを使用しています。スレッドは正常に実行されましたが、使用Thread.wait()
しているとスローされjava.lang.IllegalMonitorStateException
ます。通知されるまでスレッドを待機させるにはどうすればよいですか?
回答:
が機能するには、synchronized
ブロック内にいる必要がありますObject.wait()
。
また、古い学校のスレッドパッケージではなく、同時実行パッケージを確認することをお勧めします。それらはより安全で、作業しやすい方法です。
ハッピーコーディング。
編集
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
できる限りデータ構造を使用してください。
wait
、はい、アクセスできませんnotify
。ただし、のAPIドキュメントではObject.wait
、「スレッドはこのモニターの所有権を解放します」。そのwait
ため、それが囲んでいるsynchronized
ブロックの外側にあるかのように見えます(同じオブジェクトの場合、同じオブジェクトに複数のsynchronized
ブロックがある場合があります)。
私はこのスレッドがほぼ2年前のものであることを知っていますが、同じ問題でこのQ / Aセッションにも参加したので、これを閉じる必要があります...
違法モニター例外のこの定義を何度も読んでください...
IllegalMonitorExceptionは、スレッドがオブジェクトのモニターで待機しようとしたか、指定されたモニターを所有せずにオブジェクトのモニターで待機している他のスレッドに通知しようとしたことを示すためにスローされます。
この行は何度も何度も言っていますが、IllegalMonitorExceptionは2つの状況のいずれかが発生すると発生します。
1>指定されたモニターを所有せずにオブジェクトのモニターで待機します。
2>指定されたモニターを所有せずに、オブジェクトのモニターで待機している他のスレッドに通知します。
一部の回答が得られた可能性があります...すべてが得られない場合は、2つのステートメントを確認してください
同期(オブジェクト)
object.wait()
両方のオブジェクトが同じ場合...違法監視例外は発生しません。
もう一度IllegalMonitorExceptionの定義を読んでください。もう一度忘れないでください...
あなたのコメントに基づいて、あなたはこのようなことをしているように聞こえます:
Thread thread = new Thread(new Runnable(){
public void run() { // do stuff }});
thread.start();
...
thread.wait();
3つの問題があります。
他の人が言ったobj.wait()
ように、現在のスレッドがのプリミティブロック/ミューテックスを保持している場合にのみ呼び出すことができobj
ます。現在のスレッドがロックを保持していない場合は、表示されている例外が発生します。
thread.wait()
呼び出しは、あなたがそれを行うことを期待しているように見える何をしません。具体的にthread.wait()
は、指定されたスレッドを待機させません。むしろそれが原因現在のスレッドが他のスレッドの呼び出しまで待機しますthread.notify()
かthread.notifyAll()
。
実際には、Thread
インスタンスを停止させたくない場合に強制的に停止させる安全な方法はありません。(Javaがこれに最も近いのは非推奨のThread.suspend()
メソッドですが、Javadocで説明されているように、そのメソッドは本質的に安全ではありません。)
新しく開始したものThread
を一時停止したい場合は、CountdownLatch
インスタンスを作成await()
し、ラッチをスレッド呼び出しして一時停止するのが最善の方法です。次に、メインスレッドはcountDown()
ラッチを呼び出し、一時停止したスレッドを続行させます。
以前のポイントと直交し、Thread
オブジェクトをロック/ミューテックスとして使用すると問題が発生する可能性があります。たとえば、のjavadocはThread::join
次のように言っています。
この実装は、を
this.wait
条件とする呼び出しのループを使用しますthis.isAlive
。スレッドが終了すると、this.notifyAll
メソッドが呼び出されます。アプリケーションが使用しないことをお勧めしますwait
、notify
またはnotifyAll
上Thread
のインスタンス。
コードを投稿していないので、私たちは暗闇の中で作業しています。例外の詳細は何ですか?
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) { }
}
wait()
。
worker.wait()
ラインについて話しているのですか?次に、ロックではなくワーカーで同期する必要があります。
IllegalMonitorStateExceptionを処理するには、待機、通知、および通知のすべてのメソッドの呼び出しが、呼び出し側のスレッドが適切なモニターを所有している場合にのみ行われることを確認する必要があります。最も簡単な解決策は、これらの呼び出しを同期ブロックで囲むことです。同期ステートメントで呼び出される同期オブジェクトは、モニターを取得する必要があるオブジェクトです。
モニターの概念を理解するための簡単な例を示します
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()呼び出しは、Thread.classオブジェクトで同期するコード内で有効です。あなたが言った意味ではないと思います。
あなたが尋ねる
通知されるまでスレッドを待機させるにはどうすればよいですか?
現在のスレッドのみを待機させることができます。他のスレッドは、同意する場合にのみ、待機するように穏やかに要求されます。
何らかの条件を待つ場合は、ロックオブジェクトが必要です。Thread.classオブジェクトは非常に悪い選択です。これはシングルトンAFAIKであるため、(Thread静的メソッドを除いて)オブジェクトの同期は危険です。
同期と待機の詳細は、トム・ホーティンによってすでに説明されています。
java.lang.IllegalMonitorStateException
同期されていないオブジェクトを待機しようとしていることを意味します。これは違法です。
IllegalMonitorStateException
別のclass
/スレッドから/内のスレッドをウェイクアップしようとすると、しばらく待っていました。でjava 8
ご使用することができlock
、新たな並行処理APIの機能 の代わりのsynchronized
機能を。
私はすでにasynchronous
WebSocketトランザクションのオブジェクトをに格納していましたWeakHashMap
。私の場合の解決策は、返信用のオブジェクトも格納するlock
ことConcurrentHashMap
synchronous
でした。注意してくださいcondition.await
(ではありません.wait
)。
マルチスレッドを処理Executors.newCachedThreadPool()
するために、スレッドプールを作成するためにを使用しました。
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
}
}