webentwicklung-frage-antwort-db.com.de

java.lang.IllegalMonitorStateException: (m = null) Monitor konnte nicht abgerufen werden

Warum kann das passieren? Das Problem ist, dass das Monitorobjekt nicht sicher null ist, aber wir bekommen diese Ausnahme häufig:

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

Der Code, der dies auslöst, ist eine einfache Poollösung:

    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();
            }
        }
    }

Fehlt mir etwas?

EDIT: Die Ausnahme tritt in der available.wait();-Zeile auf.

34

Siehe den Javadoc für Object.wait.

insbesondere "Der aktuelle Thread muss der Monitor dieses Objekts sein." und "[wirft] IllegalMonitorStateException - wenn der aktuelle Thread nicht Eigentümer des Monitors des Objekts ist." Das heißt, Sie müssen das Objekt, auf das Sie warten möchten, synchronisieren.

ihr Code sollte also lauten:

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

available.wait(); muss sich in einem synchronisierten (verfügbaren) Abschnitt befinden

7
Maurice Perry

Sie erhalten die "IllegalMonitorStateException" von

available.wait()

der aktuelle Thread, der die Methode wait () aufruft, ist nicht der Eigentümer des Monitors des Objekts, der auf verweist.

Damit ein Thread Eigentümer des Monitors eines Objekts werden kann, gibt es drei Möglichkeiten.

  1. Durch Ausführen einer synchronisierten Instanzmethode dieses Objekts.
  2. Durch Ausführen des Hauptteils eines synchronisierten Blocks, der für das Objekt synchronisiert wird.
  3. Für Objekte des Typs Class durch Ausführen einer synchronisierten statischen Methode dieser Klasse.

Einfacher Beispielcode für jedes Szenario. Alle drei Codeausschnitte sind separate Klassen für jeden Typ. Kopieren Sie einfach den Code und führen Sie ihn aus. Ich habe stark in den Code Kommentare eingefügt, um zu erklären, was in jedem Fall passiert. Wenn es zu viele Kommentare für dich sind. Löschen Sie sie einfach, um den Code übersichtlicher zu gestalten.

Lesen Sie zuerst den Code in der main () -Methode, um zuerst eine Vorstellung von threadOne und threadTwo zu erhalten.

  1. Durch Ausführen einer synchronisierten Instanzmethode dieses Objekts.

    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. Durch Ausführen des Hauptteils eines synchronisierten Blocks, der für das Objekt synchronisiert wird.

    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. Für Objekte des Typs Class durch Ausführen einer synchronisierten statischen Methode dieser Klasse.

    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]....");
    
                    StaticClassReferenceClass.class.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]....");
    
                    StaticClassReferenceClass.class.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) {
            StaticClassReferenceClass mc  = new StaticClassReferenceClass();
            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
        }
    
    }
    

die takeObject () -Methode muss synchronisiert sein, oder wir müssen synchronisierte Blöcke in diese Methode schreiben. Ich hoffe, Sie sollten dafür eine Ausnahme für die Kompilierungszeit bekommen.

0
prasad