我正在使用Java中的多线程来编写程序。
我已经成功地运行了线程,但是当我使用Thread.wait()
时,它会抛出java.lang.IllegalMonitorStateException
异常。我该如何让线程等待直到被通知?
我正在使用Java中的多线程来编写程序。
我已经成功地运行了线程,但是当我使用Thread.wait()
时,它会抛出java.lang.IllegalMonitorStateException
异常。我该如何让线程等待直到被通知?
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
。然而,在Object.wait
的API文档中,“线程释放此监视器的所有权”。因此,在wait
期间,就好像它在封闭的synchronized
块之外(对于同一对象可能有多个synchronized
块)。 - Tom Hawtin - tackline我知道这个帖子已经将近两年了,但仍需要关闭它,因为我也遇到了同样的问题...
请反复阅读IllegalMonitorException的定义...
IllegalMonitorException被抛出以指示线程尝试在对象的监视器上等待或向等待对象的监视器的其他线程发出通知而没有拥有指定的监视器。
这条语句再次说明,当出现以下两种情况之一时,就会产生IllegalMonitorException....
1> 在没有拥有指定监视器的情况下等待对象的监视器。
2> 在没有拥有指定监视器的情况下通知等待对象的监视器的其他线程。
一些人可能已经得到了他们的答案...对于那些还没有得到答案的人,请检查以下两个语句....
synchronized (object)
object.wait()
如果两个object是相同的...那么不会出现illegalMonitorException。
现在再次阅读IllegalMonitorException的定义,你就不会再忘记它了...
Thread thread = new Thread(new Runnable(){
public void run() { // do stuff }});
thread.start();
...
thread.wait();
obj
的基本锁/互斥锁,则无法调用obj.wait()
。如果当前线程没有持有锁,则会出现您看到的异常。thread.wait()
调用并不像您期望的那样工作。具体来说,thread.wait()
不会导致指定的线程等待。相反,它使得当前线程等待,直到其他线程调用thread.notify()
或thread.notifyAll()
。Thread
实例。(Java最接近此功能的方法是已弃用的Thread.suspend()
方法,但该方法本质上是不安全的,如Javadoc中所解释的那样。)Thread
暂停,最好的方法是创建一个CountdownLatch
实例,并让线程调用await()
在闩锁上暂停自己。然后,主线程将在闩锁上调用countDown()
,以让暂停的线程继续执行。Thread
对象作为锁/互斥锁可能会导致问题。例如,Thread::join
的javadoc说:
此实现使用一系列基于
this.isAlive
条件的this.wait
调用。当一个线程终止时,会调用this.notifyAll
方法。建议应用程序不要在Thread
实例上使用wait
、notify
或notifyAll
。
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();
}
}
}
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()
方法的目标对象。 - Robert Munteanuworker.wait()
这一行吗?那么你应该在 worker 上进行同步,而不是在锁上进行同步。 - Robert Munteanu使用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
}
}
synchronized (lock) {
makeWakeupNeeded();
lock.notifyAll();
}
在synchronized()中,"lock"作为参数传递,并且在"lock".notifyAll();中也使用了它,这一事实非常重要。
一旦我在这两个地方都做好了,它就可以正常工作了。
wait()、notify()和notifyAll()方法应该只在同步上下文中调用。
例如,在同步块中:
syncronized (obj) {
obj.wait();
}
或者,在一个同步方法中:
syncronized static void myMethod() {
wait();
}
如果要在对象上调用wait()/notify(),则需要将其放置在同步块中。因此,首先必须锁定对象,然后才能调用这些函数。
synchronized(obj)
{
obj.wait()
}
详细解释请参见: https://dzone.com/articles/multithreading-java-and-interviewspart-2