I’m debugging an Android service written by one of our previous developers, and he’s used a Boolean in the following way:
public static class DownloadQueue extends LinkedHashMap
{
// ...
private Boolean lock = new Boolean(false);
// ...
//typical notify use
synchronized public Object addToHead(Object key, Object value)
{
// ...
synchronized (lock)
{
//IllegalMonitorStateException FROM HERE
lock.notify();
}
// ...
return null;
}
//queue machinery
public DownloadRecord getFirst()
{
// we block because queue is empty
if(this.size() == 0 || (MyApp.isInternetConnectionAvailable() == false))
{
try
{
lock = true;
synchronized (lock)
{
lock.wait(30000);
}
lock = false;
}
catch (InterruptedException e)
{}
//continue operating the queue
// ...
return value;
}
}
The documentation I’ve found on IllegalMonitorStateException suggests it’s caused by not calling notify() from a synchronized block; however, that is clearly not the case here. I did wonder if the scope of lock might be a problem, or whether the unsynchronized assignments could be. All the references to lock are of the form above, with just the one wait(long) in the queue function.
One final, possibly useful detail: this is occurring because, although our device has network, our CMS is down. We’re taking the opportunity to test the app in this condition. I suspect the queue might be operating at breakneck speed because failed downloads are getting requeued, so if a race condition is a possible cause of this fault, then it may be the cause here.
Thanks!
The problem is that you are reassigning the value of the
lockmember variable in yourgetFirstmethod.Boolean is an immutable type, so when you reassign its value you are creating a new Object.
That means you are not guaranteed to be notifying the same object that you synchronized on (if reassignment happens in between).
It is a good practice to declare lock variables as
finalto avoid this kind of programming error.