Поведение потока при блокировке переменной-члена - PullRequest
0 голосов
/ 19 марта 2019

При запуске приведенного ниже кода он генерирует IllegalMonitorStateException.

class Consumer {
    private int capacity = 5;
    private Queue<Integer> queue = new PriorityQueue<Integer>(capacity);

    class ConsumerWaitNotify implements Runnable {
        public void run() {
            try {
                consumeItem();
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();

            }
        }
        void consumeItem() {
            try {
                synchronized (queue) {            //Line 1
                    while(queue.size() == 0) {
                        System.out.format("%n%s: Waiting..Empty Queue, Size: %d%n", Thread.currentThread().getName(),
                                            queue.size());
                        wait();           //Line 2
                    }
                    int popItem = queue.poll();
                    System.out.format("%n%s: Consumes Item: %d, Size: %d", Thread.currentThread().getName(), 
                                        popItem, queue.size());
                    notify();
                }           
            } catch(InterruptedException e) {
                e.printStackTrace();

            }
        }
    }
}

public class ConsWaitNotify {

    public static void main(String[] args) {
        Consumer pc = new Consumer();
        Consumer.ConsumerWaitNotify cwn = pc.new ConsumerWaitNotify();
        Thread consumer = new Thread(cwn, "CONSUMER");
        consumer.start();

    }
}

Ниже приведена ошибка:

CONSUMER: Waiting..Empty Queue, Size: 0
Exception in thread "CONSUMER" java.lang.IllegalMonitorStateException
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Object.java:485)
    at com.threadconcurrency.lock.prodcons.Consumer$ConsumerWaitNotify.consumeItem(ConsWaitNotify.java:67)
    at com.threadconcurrency.lock.prodcons.Consumer$ConsumerWaitNotify.run(ConsWaitNotify.java:52)
    at java.lang.Thread.run(Thread.java:619)

Во время отладки я обнаружил, что, когда строка 2, то есть команда wait ()затем выполняется поток, вместо этого он выходит из состояния выполнения, он переходит к строке 1 для выполнения и выполняет его два раза.Следовательно, он выдает исключение.

Я предполагаю, что после wait поток может освободить блокировку объекта ( queue ), но все еще содержит объект класса ConsumerWaitNotify , и именно поэтому он ведет себя так.

Я добился того, чего хотел, выделив отдельный класс Consumer с помощью метода потреблениеItem () с синхронизированным (это) кодом и ConsumerWaitNotify с объектом-потребителем в качестве члена.

Но что не так в этом.Я все еще в замешательстве и не могу предсказать точное поведение.Кто-нибудь может мне помочь?

1 Ответ

1 голос
/ 19 марта 2019

Вы синхронизируете переменную queue, но вызываете wait() и notify() для объекта this.Вам нужно либо удерживать блокировку с помощью synchornized(this), либо позвонить queue.wait() и queue.notify(), чтобы убедиться, что вы уведомляете тот же монитор, для которого у вас есть блокировка.Вы можете взглянуть на документы Охраняемые блоки .

Обратите внимание, что вам не нужно создавать очередь самостоятельно.JDK предоставляет несколько реализаций java.util.concurrent.BlockingQueue:

Очередь, которая дополнительно поддерживает операции, которые ожидают, что очередь станет непустой при извлечении элемента, и ожидают места длястановятся доступными в очереди при хранении элемента.

...