IllegalMonitorStateException выбрасывается в synchronized (lock) {lock.notify ();} ... почему? - PullRequest
1 голос
/ 05 декабря 2011

Я отлаживаю сервис 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 ]

4 голосов
/ 05 декабря 2011

Проблема в том, что вы переназначаете значение переменной-члена lock в вашем методе getFirst.

Boolean является неизменным типом, поэтому при переназначении его значения вы создаете новый объект.

Это означает, что вы не гарантируете, что будете уведомлять тот же объект, который вы синхронизировали (если перераспределение происходит между ними). ​​

Рекомендуется объявлять переменные блокировки как final, чтобы избежать такой ошибки программирования.

4 голосов
/ 05 декабря 2011

Ваша синхронизация с переменной блокировки не работает, потому что вы продолжаете переназначать ее: когда вы делаете это lock = true; или lock = false;, вы меняете объект, на который ссылается «блокировка».Поэтому, когда вы получаете блокировку для него в вашем addToHead методе, а затем другой поток вызывает getFirst, ссылка на блокировку изменяется под ним, так что она указывает на что-то еще, когда вы вызываете notify.

...