我在Java中为程序使用多线程。我已经成功运行了线程,但是当我使用线程时Thread.wait()
,它正在抛出java.lang.IllegalMonitorStateException
。如何让线程等待通知它?
我在Java中为程序使用多线程。我已经成功运行了线程,但是当我使用线程时Thread.wait()
,它正在抛出java.lang.IllegalMonitorStateException
。如何让线程等待通知它?
Answers:
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会议,所以仍然需要关闭它。
请一遍又一遍地阅读对invalidMonitorException的定义...
抛出IllegalMonitorException,以指示线程试图在对象监视器上等待,或者通知其他线程在对象监视器上等待而没有拥有指定的监视器。
这行反复说,当出现两种情况之一时,IllegalMonitorException出现。
1>在不拥有指定监视器的情况下等待对象的监视器。
2>通知其他在对象监视器上等待的线程,而不拥有指定的监视器。
有些人可能会得到答案...谁都不知道,请检查2条语句...。
同步的(对象)
object.wait()
如果两个对象都相同...则不会出现非法监视器异常。
现在再次阅读IllegalMonitorException定义,您将不会再忘记它...
根据您的评论,听起来您正在执行以下操作:
Thread thread = new Thread(new Runnable(){
public void run() { // do stuff }});
thread.start();
...
thread.wait();
有三个问题。
正如其他人所说,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,必须验证只有在调用线程拥有适当的monitor的情况下,wait,notify和notifyAll方法的所有调用才发生。最简单的解决方案是将这些调用包含在同步块中。在synced语句中将调用的同步对象是必须获取其监视器的对象。
这是了解显示器概念的简单示例
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.class对象同步的代码中,Thread.wait()调用是有意义的。我认为这不是你的意思。
你问
如何使线程等待通知它?
您只能使当前线程等待。如果同意,只能轻轻地要求任何其他线程等待。
如果要等待某种条件,则需要一个锁定对象-Thread.class对象是一个非常糟糕的选择-它是单例AFAIK,因此在其上进行同步(Thread静态方法除外)很危险。
Tom Hawtin已解释了同步和等待的详细信息。
java.lang.IllegalMonitorStateException
表示您正在尝试等待未同步的对象-这样做是非法的。
我收到了一段IllegalMonitorStateException
时间,试图从另一个线程中唤醒一个class
线程。在中,java 8
您可以使用lock
新的并发API 的功能代替synchronized
功能。
我已经在将asynchronous
Websocket事务存储对象WeakHashMap
。在我的情况下,解决方案是还将对象存储lock
在ConcurrentHashMap
for 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
}
}