синхронизированный объект, не заблокированный потоком перед notifyAll()

Я хочу иметь логическое значение для уведомления некоторых разделов системы о запуске определенной службы.

По какой-то странной причине я получаю сообщение об ошибке java.lang.IllegalMonitorStateException: object not locked by thread before notifyAll().

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

Мой класс начинается так:

public class MyService {

    public static Boolean notifier = Boolean.valueOf(false);

    @Override
    public void start() {
        synchronized (MyService.notifier) {
            MyService.notifier = Boolean.valueOf(true);
            MyService.notifier.notifyAll();
        }
    }

    @Override
    public void stop() {
        synchronized (MyService.notifier) {
            MyService.notifier = Boolean.valueOf(false);
            MyService.notifier.notifyAll();
        }
    }
    ...
}

Я работаю над приложением для Android. Я не думаю, что это должно на что-то повлиять, но я дополняю вопрос этим комментарием на случай, если это повлияет на работу Java.

Почему я получаю исключение, если объект заблокирован внутри синхронизированного блока?


person J-Rou    schedule 28.12.2012    source источник
comment
Взгляните на этот вопрос SO   -  person S.R.I    schedule 28.12.2012
comment
Поскольку монитор принадлежит объекту, а не полю. Вы синхронизируете Boolean.FALSE, но уведомляете Boolean.TRUE (или наоборот).   -  person Ian Roberts    schedule 28.12.2012
comment
Мораль истории такова; Не блокируйте изменяемый объект, убедитесь, что он final Ваш код намного сложнее, чем должен быть, но я не могу предложить, чем его заменить, не видя, что вы этого ждете. (в нынешнем виде вы можете удалить все это) Я подозреваю, что ExecutorService - это то, что вам следует использовать.   -  person Peter Lawrey    schedule 28.12.2012


Ответы (1)


Линия

MyService.notifier = Boolean.valueOf(true);

заменяет объект, который вы блокируете, он перезаписывает переменную ссылкой на новый объект. Таким образом, объект, который вы заблокировали при входе в блок, отличается от того, для которого вы вызываете notifyAll. Все, что знает notifyAll, это то, что он не получил блокировку объекта, к которому он вызывается, который является новым объектом, созданным после входа в блок синхронизации.

Все потоки должны использовать один и тот же замок. Как сказал Ян Робертс, замок принадлежит объекту. Если вы перезапишете объект, у вас будет новая блокировка.

person Nathan Hughes    schedule 28.12.2012
comment
Спасибо. Я застрял с этим. - person J-Rou; 28.12.2012
comment
@J-Rou: рад помочь. все время от времени застревают, это профессиональный риск. - person Nathan Hughes; 29.12.2012