IllegalMonitorStateException在其运行方法的线程上调用wait()(没有同步块) [英] IllegalMonitorStateException calling wait() on a thread inside its run method (with no synchronized block)

查看:130
本文介绍了IllegalMonitorStateException在其运行方法的线程上调用wait()(没有同步块)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我订购以确保在套接字关闭时停止从套接字读取数据的线程(由于事实 socket.isClosed()不起作用如预期)我写了一个心跳来检查套接字是否仍然打开。在BufferedReader开始读取套接字之前,调用方法 startHeartbeat(),当 isClosed()是false。

I order to ensure that the thread which is reading data from a socket is stopped when the socket closes (due to the fact socket.isClosed() doesn't work as expected) I wrote a "heartbeat" to check if the socket is still open. The method startHeartbeat() is called just before the BufferedReader starts reading the socket, and it only starts reading when isClosed() is false.

这里有一些同步的方法,但不像其他类似的问题, wait()调用不在一个方法之内。以下是基本代码:

There are some synchronized methods in play here, but unlike other similar questions, the wait() call is not within one of the methods. Here is the essential code:

synchronized boolean isClosed()
{
    return closed;
}

synchronized void setClosed(boolean b)
{
    closed = b;
}

//We need to make sure that the socket is still online, to ensure the reading stops when the connection closes.
void startHeartbeat()
{
    Thread heartbeat = new Thread()
    {
        public void run()
        {
            while (true)
            {
                try
                {
                    post(THUMP_THUMP);
                    setClosed(false);
                }
                catch (IOException e)
                {
                    setClosed(true);
                }
                finally
                {
                    try
                    {
                        this.wait(PULSE); //Exception here!
                    }
                    catch (InterruptedException e) {}
                }
            }
        }
    };
    heartbeat.setDaemon(true);
    heartbeat.start();
}

THUMP_THUMP只是一个发送出来的常量字符串($ code> post()方法只是在 BufferedWriter 中写出对象,而PULSE是节拍之间的时间。

THUMP_THUMP is just a constant string that is sent out (the post() method just writes the object out on a BufferedWriter) and PULSE is the time between beats.

我不知道为什么在阅读各种线程之后,我们明白为什么他们 IllegalMonitorStateException 异常)和阅读API的异常。有没有人可以告诉我我在做什么错?

I'm not sure why there is an IllegalMonitorStateException here, after reading various threads (I understand why they have the exception) and reading the API for the exception. Can anybody tell me what I am doing wrong here?

推荐答案


有人可以告诉我我是什么在这里做错?

Can anybody tell me what I am doing wrong here?

是的 - 你不是在等待的对象上进行同步。 API文档很漂亮清除:

Yes - you're not synchronizing on the object you're waiting on. The API documentation is pretty clear:


抛出:

IllegalMonitorStateException - 如果当前线程不是对象监视器的所有者。

Throws:
IllegalMonitorStateException - if the current thread is not the owner of the object's monitor.

重要的是要明白对象监视器的所有者基本上意味着是在使用该对象的同步块中。同步块在开始时获取相关对象的监视器,并在最后释放它。从 Java教程同步

It's important to understand that "owner of the objects monitor" basically means "is in a synchronized block using that object". A synchronized block acquires the relevant object's monitor at the start, and releases it at the end. From the Java tutorial on synchronization:


同步是围绕一个称为内在锁或监视器锁的内部实体构建的。 (API规范通常将该实体简称为监视器)。内在锁在同步的两个方面发挥作用:强制执行对对象状态的独占访问,并建立对可见性至关重要的发生关系。

Synchronization is built around an internal entity known as the intrinsic lock or monitor lock. (The API specification often refers to this entity simply as a "monitor.") Intrinsic locks play a role in both aspects of synchronization: enforcing exclusive access to an object's state and establishing happens-before relationships that are essential to visibility.

每个对象都有一个与之相关的固有锁。按照约定,需要对对象的字段进行排他性和一致性访问的线程必须在访问对象的内部锁之前获取对象的固有锁,然后在完成对象时释放内部锁。据说线程在获得锁定和释放锁定的时间之间拥有固有的锁定。只要一个线程拥有固有的锁,没有其他线程可以获得同一个锁。另一个线程在尝试获取锁定时将阻止。

Every object has an intrinsic lock associated with it. By convention, a thread that needs exclusive and consistent access to an object's fields has to acquire the object's intrinsic lock before accessing them, and then release the intrinsic lock when it's done with them. A thread is said to own the intrinsic lock between the time it has acquired the lock and released the lock. As long as a thread owns an intrinsic lock, no other thread can acquire the same lock. The other thread will block when it attempts to acquire the lock.

...

当线程调用一个synchronized方法,它自动获取该方法的对象的内在锁,并在方法返回时释放它。即使返回是由于未捕获的异常引起的,也会发生锁定释放。

When a thread invokes a synchronized method, it automatically acquires the intrinsic lock for that method's object and releases it when the method returns. The lock release occurs even if the return was caused by an uncaught exception.

...

另一种方式创建同步代码是同步语句。与同步方法不同,synchronized语句必须指定提供内在锁的对象[...]

Another way to create synchronized code is with synchronized statements. Unlike synchronized methods, synchronized statements must specify the object that provides the intrinsic lock [...]

在代码中,当前线程是 这个的所有者,因为你没有同步 - 因此是例外。你必须同步 - 记住, wait()发布显示器,然后在返回之前重新获取。

In your code, the current thread is not the owner of this, because you're not synchronizing - hence the exception. You must synchronize - remember that wait() will release the monitor, then reacquire it before returning.

作为旁注,我强烈推荐使用 使用线程对象的监视器同步,等待,通知等 - 线程中的代码已经这样做了,所以你的代码和代码可能会很容易相互干扰。我建议创建一个单独的对象,仅用于同步/等待/通知。

As a side-note, I'd strongly recommend against using a Thread object's monitor for synchronization, waiting, notifying etc - code within Thread already does that, so your code and its code could easily interfere with each other. I'd recommend creating a separate object solely for the purpose of synchronization/wait/notify.

这篇关于IllegalMonitorStateException在其运行方法的线程上调用wait()(没有同步块)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆