(Java) Потокобезопасность с использованием Object wait () и notify () - PullRequest
0 голосов
/ 06 апреля 2020

Я искал способ заставить один поток ждать / спать, пока другой поток не сигнализировал, что что-то было готово. Ожидающий поток должен проснуться, обработать данные, которые были сделаны доступными, а затем go вернуться в спящий режим, пока другой поток снова не подаст сигнал.

Самый простой метод, который я смог найти, был Object.wait() и Object.notify(), который ведет себя как семафор, инициализированный значением 0. Однако без операторов synchronized около notify/wait, Java всегда выдает IllegalMonitorStateException, когда поток не является владельцем монитора. Поэтому я просто поместил их вокруг кода, как показано ниже.

THREAD 1: бесконечный запуск l oop

public class Main {
    private Handler handler; // only one instance (singleton pattern)

    public void listen() {
        while (true) {
            try {
                synchronized (handler) { 
                    handler.wait();
                    int value = handler.getSize();
                    // do something
                }
            } catch (InterruptedException e) {
                // ...
            }
        }
    }
}

THREAD 2: Некоторые другие вызовы класса removeItem

public class Handler {

    // SINGLETON PATTERN - ONLY ONE INSTANCE

    private ArrayList<Integer> sharedList;

    private Handler() {
        sharedList = new ArrayList<>();
    }

    public void addItem(Integer i) {
        synchronized (sharedList) {
            // add to list
        }
    }

    public void removeItem(int i) {
        synchronized (sharedList) {
            // remove item

            // notify that something is removed
            synchronized (this) {
                this.notify(); // this == handler
            }
        }
    }

    public int getSize() {
        synchronized (sharedList) {
            return sharedList.size();
        }
    }
}

Кажется, что он работает отлично, но не уверен, что есть скрытая ошибка. Мой вопрос: это безопасно? wait снимает ли блокировку экземпляра для handler/this, чтобы notify могла получить блокировку?

1 Ответ

1 голос
/ 06 апреля 2020

Синхронизированные блоки безопасны. Оператор synchronized(obj) получает блокировку аргумента obj, поэтому вы можете вызвать wait и notify для него. Они оба требуют, чтобы текущий поток удерживал блокировку объекта.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...