Почему notifyAll() вызывает исключение IllegalMonitorStateException при синхронизации с целым числом?

StackOverflow https://stackoverflow.com/questions/260337

Вопрос

Почему эта тестовая программа приводит к java.lang.IllegalMonitorStateException?

public class test {
    static Integer foo = new Integer(1);
    public static void main(String[] args) {
        synchronized(foo) {
            foo++;
            foo.notifyAll();
        }
        System.err.println("Success");
    }
}

Результат:

Exception in thread "main" java.lang.IllegalMonitorStateException
        at java.lang.Object.notifyAll(Native Method)
        at test.main(test.java:6)
Это было полезно?

Решение

Вы правильно заметили , что notifyAll должен быть вызван из синхронизированного блока.

Однако в вашем случае из-за автоматической упаковки объект, с которым вы синхронизировались, не является тем же экземпляром, который вы вызвали notifyAll вкл.Фактически, новый, увеличенный foo экземпляр по-прежнему ограничен стеком, и никакие другие потоки не могут быть заблокированы на wait звони.

Вы могли бы реализовать свой собственный изменяемый счетчик, по которому выполняется синхронизация.В зависимости от вашего приложения вы также можете обнаружить, что Атомарный интегратор отвечает вашим потребностям.

Другие советы

Вы также должны с осторожностью относиться к блокировке или уведомлению таких объектов, как String и Integer, которые могут быть интернированы JVM (чтобы предотвратить создание большого количества объектов, представляющих целое число 1 или строку "").

Увеличение целого числа приводит к исчезновению старого foo и замене его совершенно новым объектом foo, который не синхронизирован с предыдущей переменной foo.

Вот реализация AtomicInteger, которую Эриксон предложил выше.В этом примере foo.notifyAll();не создает java.lang.Исключение IllegalMonitorStateException, потому что объект AtomicInteger не обновляется при foo.incrementAndGet();является запущенным.

import java.util.concurrent.atomic.AtomicInteger;

public class SynchronizeOnAPrimitive {
    static AtomicInteger foo = new AtomicInteger(1);
    public static void main(String[] args) {
        synchronized (foo) {
            foo.incrementAndGet();
            foo.notifyAll();
        }
        System.out.println("foo is: " + foo);
    }
}

Выходной сигнал:

foo is: 2

Как отметил Эриксон, код без оператора постинкремента работает без ошибок:

static Integer foo = new Integer(1);

public static void main(String[] args) {
    synchronized (foo) {
        foo.notifyAll();
    }
    System.out.println("Success");
}

выходной сигнал:

Успех

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top