简体   繁体   中英

IllegalMonitorStateException calling wait() on a thread inside its run method (with no synchronized block)

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.

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 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.

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?

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

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

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 :

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.

...

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.

...

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM