3 votes

Pourquoi ce code lève une IllegalStateMonitorException ?

J'essaie de créer une file d'attente bloquante en utilisant les méthodes notifyAll() et wait() avec un objet partagé. Mais ce code lève une IllegalMonitorStateException. Où dois-je apporter la modification ?

public class BlockingQueueNotifyAll<E> {

    private Queue<E> queue;
    private int max;
    private Object sharedQ = new Object();

    public BlockingQueueNotifyAll(int size) {
        queue = new LinkedList<>();
        this.max = size;
    }

    public synchronized void put(E e) {
        while(queue.size() == max) {
            try {
                sharedQ.wait();
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
        }
        queue.add(e);
        sharedQ.notifyAll();
    }

    public synchronized E take() throws InterruptedException {

        while(queue.size() == 0) {
            sharedQ.wait();
        }
        E item = queue.remove();
        sharedQ.notifyAll();
        return item;
    }
}

4voto

michalk Points 6599

Le problème est que vous appelez notifyAll y wait sur sharedQ mais vous ne le faites pas en tenant le verrou sur sharedQ objet. synchronized sur vos méthodes vous assurera d'acquérir un verrouillage sur BlockingQueueNotifyAll objet.

De Object::wait docs :

Le thread actuel doit posséder le moniteur de cet objet.

synchronized (obj) {  // here you acquire lock on obj
         while (<condition does not hold>)
             obj.wait();  // here you call wait on obj while holding the lock on this object
         ... // Perform action appropriate to condition
}

Donc, dans votre cas, vous appelez wait y notifyAll sur un objet alors qu'il ne détient pas le verrou sur cet objet.

0voto

user3603523 Points 31

Donc ce code fonctionne

public class BlockingQueueNotifyAll<E> {

    private Queue<E> queue;
    private int max;
    private Object sharedQ = new Object();

    public BlockingQueueNotifyAll(int size) {
        queue = new LinkedList<>();
        this.max = size;

    }

    public void put(E e) {

        synchronized (sharedQ) {
            while (queue.size() == max) {

                try {
                    sharedQ.wait();
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }

            }
            queue.add(e);
            sharedQ.notifyAll();
        }
    }

    public E take() throws InterruptedException {

        synchronized (sharedQ) {
            while (queue.size() == 0) { // replace if with an while

                sharedQ.wait();
            }
            E item = queue.remove();
            sharedQ.notifyAll();
            return item;

        }
    }

 }

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X