locke
locke

Reputation: 85

IllegalMonitorStateException on Thread.notify() within synchronized

This is in an Android app. We have a class that manages socket communication with a server, and that class has threads for sending and receiving messages. We are occasionally getting an IllegalMonitorStateException in the method that sends messages to a handler and then notifies the 'send thread' so that it will read the message from the handler and send it to the server:

java.lang.IllegalMonitorStateException: object not locked by thread before notify()
at java.lang.Object.notify(Native Method)
at com.company.appname.package.ServerConnection.sendMessageToServer(ServerConnection.java:448)
at com.company.appname.package.ServerConnection.sendMessageToServer(ServerConnection.java:418)
at com.company.appname.package.ServerConnection.gotResponse(ServerConnection.java:403)
at com.company.appname.package.ServerConnection.gotConnected(ServerConnection.java:349)
at com.company.appname.package.ServerEventHandler.handleMessage(ServerEventHandler.java:59)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5001)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
at dalvik.system.NativeStart.main(Native Method)

The exception occurs at mMessageSendThreadForServer.notify(); in the below code.

public class MessageSendThread extends Thread {
    ...
}

public class ServerConnection {
    ...
    private final Object mMessageSendThreadForServerLock = new Object();
    private MessageSendThread mMessageSendThreadForServer;
    ...
    private void sendMessageToForServer(String msg) 
    {
        ...
        // Wake the sending thread
        synchronized(mMessageSendThreadForServerLock) 
        {
            synchronized(mMessageSendThreadForServer) 
            {
                mMessageSendThreadForServer.notify();
            }
        }
    }
    ...
}

All documentation and other issues I've found indicate that this should't be capable of causing the IllegalMonitorStateException. I've seen many issues where people change the object within the synchronize but all we are doing within the synchronize is calling notify().

Any ideas are appreciated. I am stumped.

Upvotes: 1

Views: 221

Answers (1)

Dev
Dev

Reputation: 12206

There is nothing wrong with the code snippet you presented, but it can be modified to bulletproof it.

Try this snippet and see what happens. It protects against another thread changing the reference.

...
// Wake the sending thread
synchronized(mMessageSendThreadForServerLock) 
  final MessageSendThread sendThread = mMessageSendThreadForServer;
  synchronized(sendThread) 
  {
    sendThread.notify();
  }
}
...

Upvotes: 2

Related Questions