Почему notifyAll() вызывает исключение IllegalMonitorStateException при синхронизации с Integer?
Почему эта тестовая программа приводит к 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)
4 ответа
Вы правильно отметили, что notifyAll
должен быть вызван из синхронизированного блока.
Однако в вашем случае из-за автобокса объект, с которым вы синхронизировались, не тот экземпляр, который вы вызывали notifyAll
на. На самом деле, новый, увеличенный foo
экземпляр по-прежнему ограничен стеком, и никакие другие потоки не могут быть заблокированы на wait
вызов.
Вы можете реализовать свой собственный изменяемый счетчик, на котором выполняется синхронизация. В зависимости от вашего приложения вы также можете обнаружить, что AtomicInteger отвечает вашим потребностям.
Вам также следует опасаться блокирования или уведомления о таких объектах, как String и Integer, которые могут быть интернированы JVM (чтобы предотвратить создание большого количества объектов, представляющих целое число 1 или строку "").
Увеличение Integer приводит к исчезновению старого 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
Как заметил Эриксон, код без оператора postincrement работает без ошибок:
static Integer foo = new Integer(1);
public static void main(String[] args) {
synchronized (foo) {
foo.notifyAll();
}
System.out.println("Success");
}
выход:
успех