Подтвердить что ты не робот

Java.lang.IllegalMonitorStateException: (m = null) Не удалось получить монитор для

Почему это может случиться? Дело в том, что объект монитора не является нулевым, но все же мы получаем это исключение довольно часто:

java.lang.IllegalMonitorStateException: (m=null) Failed to get monitor for (tIdx=60)
        at java.lang.Object.wait(Object.java:474)
        at ...

Код, который провоцирует это, представляет собой простое решение пула:

    public Object takeObject() {
        Object obj = internalTakeObject();
        while (obj == null) {
            try {
                available.wait();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            obj = internalTakeObject();
        }
        return obj;
    }

    private Object internalTakeObject() {
        Object obj = null;
        synchronized (available) {
            if (available.size() > 0) {
                obj = available.keySet().iterator().next();
                available.remove(obj);
                synchronized (taken) {
                    taken.put(obj, Boolean.valueOf(true));
                }
            }
        }
        return obj;
    }

    public void returnObject(Object obj) {
        synchronized (taken) {
            taken.remove(obj);
        }
        synchronized (available) {
            if (available.size() < size) {
                available.put(obj, Boolean.valueOf(true));
                available.notify();
            }
        }
    }

Я что-то пропустил?

EDIT: исключение происходит в строке available.wait();.

4b9b3361

Ответ 1

См. javadoc для Object.wait.

в частности "Текущий поток должен владеть этим объектом монитора". и "[бросает] IllegalMonitorStateException - если текущий поток не является владельцем монитора объекта". То есть вам нужно синхронизировать объект, на который вы собираетесь называть wait.

поэтому ваш код должен быть:

synchronized (available) {
    available.wait();
}

Ответ 2

available.wait(); должен находиться в синхронизированной (доступной) секции

Ответ 3

Метод takeObject() должен быть синхронизирован или нам нужно написать синхронизированный блок внутри этого метода. Надеюсь, у вас должно быть исключение времени компиляции для этого.

Ответ 4

Вы получаете "IllegalMonitorStateException" от

available.wait()

потому что текущий поток, который вызывает метод wait(), не является владельцем монитора объектов, на который ссылается "доступная" ссылка на объект.

Чтобы поток стал владельцем монитора объектов, есть 3 способа.

  1. Выполняя синхронизированный метод экземпляра этого объекта.
  2. Выполняя тело синхронизированного блока, который синхронизируется на объекте.
  3. Для объектов типа Class путем выполнения синхронизированного статического метода этого класса.

Простой пример кода для каждого сценария. Все три фрагмента кода являются отдельными классами для каждого типа, просто скопируйте код и запустите его. Я добавил комментарии в код, чтобы объяснить, что происходит в каждом случае. Если это слишком много комментариев для вас. просто удалите их, чтобы сделать код более кратким.

Кроме того, сначала прочтите код в методе main(), чтобы получить представление о threadOne и threadTwo.

  1. Выполняя синхронизированный метод экземпляра этого объекта.

    import static java.lang.System.out;
    
    public class SynchronizedInstanceMethodClass {
    
        synchronized void synchronizedInstanceMethod() { // threadOne acquire the monitor for "this" and continue.
    
                try {
    
                    out.println("EVENT #1 threadOne is about to strat waiting on the "
                            +"monitor it already has - [\"this\"]....");
    
                    this.wait(); // The threadOne already have the monitor for "this", 
                                //  just release the monitor and go and wait threadOne.
    
                    out.println("EVENT #3 Notify received and continue execution...");
    
                } catch (InterruptedException interruptedException) {
                    interruptedException.printStackTrace();
                }
        }
    
    
        synchronized void notifierForAllThreads() { // threadTwo acquire the monitor for "this", 
                                                   // which was released by threadOne when it went to waiting and contine.
    
                out.println("EVENT #2 threadTwo is about to notify all threads(including threadOne) "
                        +"   waiting on the monitor of -[\"this\"]....");
    
                this.notifyAll(); // threadTwo who owns the monitor on "this" notifies all 
                                 // threads waiting on "this" and releases the monitor
        }
    
        public static void main(String [] args) {
    
            SynchronizedInstanceMethodClass mc  = new SynchronizedInstanceMethodClass();
            Thread threadOne = new Thread(() -> {mc.synchronizedInstanceMethod();});
            Thread threadTwo = new Thread(() -> {mc.notifierForAllThreads();});
    
            threadOne.start(); // Start the waiting of Thread one
            threadTwo.start(); // Notify the waiting threadOne
        }
    
    }
    
  2. Выполняя тело синхронизированного блока, который синхронизируется на объекте.

    import static java.lang.System.out;
    
    public class SynchronizedBlockClass {
    
        void synchronizedBlockInstanceMethod() {
    
            synchronized (this) { // threadOne acquire the monitor for "this" and continue.
    
                try {
    
                    out.println("EVENT #1 threadOne is about to strat waiting on the "
                                +"monitor it already has - [\"this\"]....");
    
                    this.wait(); // The threadOne already have the monitor for "this", 
                                //  just release the monitor and go and wait threadOne.
    
                    out.println("EVENT #3 Notify received and continue execution...");
                } catch (InterruptedException interruptedException) {
                    interruptedException.printStackTrace();
                }
            }
        }
    
    
        void synchronizedBlockNotifierForAllThreads() {
    
            synchronized (this) { // threadTwo acquire the monitor for "this", 
                                 // which was released by threadOne when it went to waiting and continue.
    
                    out.println("EVENT #2 threadTwo is about to notify all threads(including threadOne) "
                            +"   waiting on the monitor of -[\"this\"]....");
    
                    this.notifyAll(); // threadTwo who owns the monitor on "this" notifies all 
                                     // threads waiting on "this" and releases the monitor
                }
        }
    
        public static void main(String [] args) {
            SynchronizedBlockClass mc  = new SynchronizedBlockClass();
            Thread threadOne = new Thread(() -> {mc.synchronizedBlockInstanceMethod();});
            Thread threadTwo = new Thread(() -> {mc.synchronizedBlockNotifierForAllThreads();});
    
            threadOne.start(); // Start the waiting of Thread one
            threadTwo.start(); // Notify the waiting threadOne
        }
    
    }
    
  3. Для объектов типа Class путем выполнения синхронизированного статического метода этого класса.

    import static java.lang.System.out;
    
    public class StaticClassReferenceClass {
    
        void synchronizedBlockInstanceMethod() {
    
            synchronized (StaticClassReferenceClass.class) { // threadOne acquire the monitor for class literal and continue.
    
                try {
    
                    out.println("EVENT #1 threadOne is about to strat waiting on the "
                                +"monitor it already has - [StaticClassReferenceClass.class]....");
    
                    this.wait(); // The threadOne already have the monitor for the class literal, 
                                //  So it just release the monitor and go and wait.
    
                    out.println("EVENT #3 Notify received and continue execution...");
                } catch (InterruptedException interruptedException) {
                    interruptedException.printStackTrace();
                }
            }
        }
    
    
        void synchronizedBlockNotifierForAllThreads() {
    
            synchronized (StaticClassReferenceClass.class) { // threadTwo acquire the monitor for the class literal, 
                                 // which was released by threadOne when it went to waiting.
    
                    out.println("EVENT #2 threadTwo is about to notify all threads(including threadOne) "
                            +"   waiting on the monitor of -[StaticClassReferenceClass.class]....");
    
                    this.notifyAll(); // threadTwo who owns the monitor on the class literal notifies all 
                                     // threads waiting on it and releases the monitor
                }
        }
    
        public static void main(String [] args) {
            SynchronizedBlockClass mc  = new SynchronizedBlockClass();
            Thread threadOne = new Thread(() -> {mc.synchronizedBlockInstanceMethod();});
            Thread threadTwo = new Thread(() -> {mc.synchronizedBlockNotifierForAllThreads();});
    
            threadOne.start(); // Start the waiting of Thread one
            threadTwo.start(); // Notify the waiting threadOne
        }
    
    }