在synchronized(lock){lock.notify();}中抛出IllegalMonitorStateException ...为什么?

时间:2011-12-05 16:00:36

标签: android exception locking notify

我正在调试我们之前的一位开发人员编写的Android服务,并且他以下列方式使用了Boolean

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;
    }
}

我在IllegalMonitorStateException上找到的文档表明,这是因为没有从notify()块调用synchronized而导致的。然而,这显然不是这种情况。我确实想知道lock的范围是否可能是一个问题,或者是否可能存在未同步的分配。所有对lock的引用都是上面的形式,只有队列函数中的一个wait(long)

最后一个可能有用的细节:这是因为虽然我们的设备有网络,但我们的CMS已关闭。我们正抓住机会在这种情况下测试应用程序。我怀疑队列可能以极快的速度运行,因为下载失败会被重新排队,因此如果竞争条件是导致此故障的可能原因,那么这可能就是原因。

谢谢!

2 个答案:

答案 0 :(得分:4)

您对锁变量的同步不起作用,因为您不断重新分配它:当您执行此操作lock = true;lock = false;时,您正在更改“锁定”所指的对象。因此,当您在addToHead方法中获取锁定然后另一个线程调用getFirst时,锁定的引用会在其下方更改,因此在您调用notify时它会指向其他内容。

答案 1 :(得分:4)

问题是您要在lock方法中重新分配getFirst成员变量的值。

布尔值是一个不可变类型,因此当您重新分配其值时,您将创建一个新的对象。

这意味着您无法保证通知您同步的同一对象(如果在其间发生重新分配)。

将锁变量声明为final是一种很好的做法,可以避免这种编程错误。